﻿"""
@Project ：utils
@File    ：text_to_speech_data.py
@IDE     ：PyCharm
@Author  ：靓仔
@Date    ：2025/2/13 14:24
"""
import sys
import asyncio
import edge_tts
import os
import tempfile
import mmap
import gc
from collections import deque
import re
import threading
import concurrent.futures
import multiprocessing
import time
from threading import Lock
import chardet  # 用于检测文件编码
import json
import csv
import xml.etree.ElementTree as ET
from urllib.parse import urlparse
import requests
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
                             QHBoxLayout, QLabel, QTextEdit, QPushButton,
                             QComboBox, QFileDialog, QProgressBar, QSlider,
                             QCheckBox, QLineEdit, QGridLayout)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer
from PyQt5.QtGui import QIcon, QFont
import aiohttp
import socket

# ==================== 配置加载器 ====================
class ConfigLoader:
    """配置加载器单例 - 统一管理配置导入"""
    _instance = None
    _config_module = None
    _config_loaded = False
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance
    
    def __init__(self):
        if not ConfigLoader._config_loaded:
            self._load_config()
            ConfigLoader._config_loaded = True
    
    def _load_config(self):
        """加载配置模块"""
        try:
            import config
            ConfigLoader._config_module = config
            print("[配置] 配置模块加载成功")
        except ImportError:
            ConfigLoader._config_module = None
            print("[配置] 配置模块不可用，使用默认配置")
    
    def is_available(self):
        """检查配置模块是否可用"""
        return ConfigLoader._config_module is not None
    
    def is_mega_text(self, text_length):
        """检查是否为超大文本"""
        if self.is_available():
            return ConfigLoader._config_module.is_mega_text(text_length)
        return text_length >= 300000  # 默认阈值
    
    def get_mega_text_config(self, config_type):
        """获取超大文本配置"""
        if self.is_available():
            return ConfigLoader._config_module.get_mega_text_config(config_type)
        # 返回默认配置
        defaults = {
            'concurrency': {'max_workers': 64, 'min_workers': 16},
            'segmentation': {'max_length': 2500, 'min_length': 1500, 
                           'target_segments': 120, 'smart_merge_threshold': 800},
            'memory': {'cache_size': 3 * 1024 * 1024 * 1024, 
                      'in_memory_threshold': 10 * 1024 * 1024, 
                      'prealloc_temp_files': 200},
            'network': {'total_connections': 12, 'connections_per_host': 6,
                       'keepalive_timeout': 60, 'retry_attempts': 3,
                       'retry_delay': 2.0, 'rate_limit_delay': 0.5},
            'streaming': {'enable_streaming_merge': True, 
                         'merge_chunk_size': 2 * 1024 * 1024,
                         'concurrent_mergers': 4}
        }
        return defaults.get(config_type, {})
    
    def auto_detect_performance_mode(self, text_length):
        """自动检测性能模式"""
        if self.is_available():
            return ConfigLoader._config_module.auto_detect_performance_mode(text_length)
        if text_length >= 500000:
            return "超级模式"
        elif text_length >= 300000:
            return "超大模式"
        elif text_length >= 100000:
            return "大文本模式"
        else:
            return "标准模式"

# 全局配置加载器实例
config_loader = ConfigLoader()


# ==================== 文本分割器 ====================
class TextSegmenter:
    """统一的文本分割器 - 消除重复代码"""
    
    def __init__(self, text_length=0):
        self.text_length = text_length
        
    def split_text(self, text, max_length=1000, min_length=100):
        """智能自适应文本分割
        
        Args:
            text: 待分割的文本
            max_length: 最大段落长度（硬限制）
            min_length: 最小段落长度（避免过度分割）
        
        Returns:
            list: 分割后的文本段落列表
        """
        text = text.strip()
        if not text:
            return []
        
        text_length = len(text)
        
        # 检查是否为超大文本
        if config_loader.is_mega_text(text_length):
            detected_mode = config_loader.auto_detect_performance_mode(text_length)
            print(f"🚀 检测到文本长度: {text_length:,} 字符，自动启用 {detected_mode} 模式")
            return self._split_mega_text(text)
        
        # 动态调整分段参数
        if text_length > 100000:  # 10万字符以上
            max_length = min(1800, max_length * 2)
            min_length = max(800, min_length * 4)
            print(f"📊 大文本优化: 分段参数调整为 {min_length}-{max_length} 字符")
        elif text_length > 30000:  # 3万字符以上
            max_length = min(1200, max_length * 1.5)
            min_length = max(400, min_length * 2)
        
        # 如果文本很短，不分割
        if text_length <= min_length:
            return [text]
        
        # 首先按自然段落分割
        paragraphs = [p.strip() for p in text.split('\n\n') if p.strip()]
        if not paragraphs:
            paragraphs = [text]
        
        segments = []
        
        for paragraph in paragraphs:
            if len(paragraph) <= max_length:
                segments.append(paragraph)
            else:
                segments.extend(self._split_long_paragraph(paragraph, max_length, min_length))
        
        # 合并过短的段落以提高效率
        final_segments = self._merge_short_segments(segments, min_length, max_length)
        
        print(f"✅ 文本分段完成: {len(final_segments)} 个段落 (平均 {text_length//len(final_segments):,} 字符/段)")
        return final_segments
    
    def _split_long_paragraph(self, paragraph, max_length, min_length):
        """优化的长段落分割"""
        sentences = []
        
        # 快速分割：只按主要句末标点分割
        parts = re.split(r'([。！？])', paragraph)
        
        # 重新组合句子（保留标点）
        current_sentence = ""
        for i, part in enumerate(parts):
            if part in '。！？':
                current_sentence += part
                if current_sentence.strip():
                    sentences.append(current_sentence.strip())
                current_sentence = ""
            else:
                current_sentence += part
        
        if current_sentence.strip():
            sentences.append(current_sentence.strip())
        
        # 如果没有找到句子，按逗号分割
        if not sentences or len(sentences) == 1:
            sentences = [s.strip() for s in paragraph.split('，') if s.strip()]
        
        if not sentences:
            sentences = [paragraph]
        
        # 将句子组合成合适大小的段落
        segments = []
        current_segment = ""
        
        for sentence in sentences:
            if len(sentence) > max_length:
                if current_segment:
                    segments.append(current_segment.strip())
                    current_segment = ""
                segments.extend(self._simple_force_split(sentence, max_length))
                continue
            
            if not current_segment:
                current_segment = sentence
            elif len(current_segment) + len(sentence) + 1 <= max_length:
                current_segment += " " + sentence
            else:
                segments.append(current_segment.strip())
                current_segment = sentence
        
        if current_segment:
            segments.append(current_segment.strip())
        
        return [s for s in segments if s]
    
    def _simple_force_split(self, sentence, max_length):
        """简化的强制分割"""
        if len(sentence) <= max_length:
            return [sentence]
        
        segments = []
        remaining = sentence
        
        while len(remaining) > max_length:
            best_split = max_length
            
            # 快速查找逗号分割点
            comma_pos = remaining.rfind('，', max_length // 2, max_length)
            if comma_pos != -1:
                best_split = comma_pos + 1
            else:
                # 查找空格分割点
                space_pos = remaining.rfind(' ', max_length // 2, max_length)
                if space_pos != -1:
                    best_split = space_pos + 1
            
            segment = remaining[:best_split].strip()
            if segment:
                segments.append(segment)
            remaining = remaining[best_split:].strip()
        
        if remaining:
            segments.append(remaining)
        
        return segments
    
    def _merge_short_segments(self, segments, min_length, max_length):
        """合并过短的段落以提高处理效率"""
        if not segments:
            return []
        
        merged = []
        current_group = ""
        
        for segment in segments:
            if not current_group:
                current_group = segment
            elif len(current_group) + len(segment) + 1 <= max_length:
                if len(current_group) < min_length or len(segment) < min_length:
                    current_group += "\n" + segment
                else:
                    merged.append(current_group)
                    current_group = segment
            else:
                merged.append(current_group)
                current_group = segment
        
        if current_group:
            merged.append(current_group)
        
        return [s.strip() for s in merged if s.strip()]
    
    def _split_mega_text(self, text):
        """超大文本专用分段算法 - 30万字以上优化"""
        config = config_loader.get_mega_text_config('segmentation')
        
        max_length = config.get('max_length', 2500)
        min_length = config.get('min_length', 1500)
        target_segments = config.get('target_segments', 120)
        smart_merge_threshold = config.get('smart_merge_threshold', 800)
        
        print(f"🔥 启用超大文本分段: 目标 {target_segments} 段，{min_length}-{max_length} 字符/段")
        
        text_length = len(text)
        ideal_segment_size = text_length // target_segments
        ideal_segment_size = max(min_length, min(ideal_segment_size, max_length))
        
        print(f"📐 理想分段大小: {ideal_segment_size} 字符")
        
        # 第一步：按自然段落分割
        natural_paragraphs = [p.strip() for p in text.split('\n\n') if p.strip()]
        if not natural_paragraphs:
            natural_paragraphs = [text]
        
        # 第二步：智能合并和分割
        segments = []
        current_segment = ""
        
        for paragraph in natural_paragraphs:
            if len(paragraph) > max_length:
                if current_segment.strip():
                    segments.append(current_segment.strip())
                    current_segment = ""
                
                long_segments = self._split_mega_paragraph(paragraph, ideal_segment_size, max_length, min_length)
                segments.extend(long_segments)
            else:
                potential_length = len(current_segment) + len(paragraph) + 2
                
                if potential_length <= ideal_segment_size or len(current_segment) < min_length:
                    if current_segment:
                        current_segment += "\n\n" + paragraph
                    else:
                        current_segment = paragraph
                else:
                    if current_segment.strip():
                        segments.append(current_segment.strip())
                    current_segment = paragraph
        
        if current_segment.strip():
            segments.append(current_segment.strip())
        
        # 第三步：智能后处理
        final_segments = self._smart_merge_segments(segments, smart_merge_threshold, max_length)
        
        print(f"🎯 超大文本分段完成: {len(final_segments)} 段 (目标 {target_segments} 段)")
        print(f"📊 平均段落长度: {sum(len(s) for s in final_segments) // len(final_segments):,} 字符")
        
        return final_segments
    
    def _split_mega_paragraph(self, paragraph, ideal_size, max_length, min_length):
        """分割超长段落"""
        if len(paragraph) <= max_length:
            return [paragraph]
        
        sentences = re.split(r'([。！？；])', paragraph)
        
        sentence_list = []
        current = ""
        for i, part in enumerate(sentences):
            if part in '。！？；':
                current += part
                if current.strip():
                    sentence_list.append(current.strip())
                current = ""
            else:
                current += part
        
        if current.strip():
            sentence_list.append(current.strip())
        
        segments = []
        current_segment = ""
        
        for sentence in sentence_list:
            potential_length = len(current_segment) + len(sentence)
            
            if potential_length <= ideal_size or len(current_segment) < min_length:
                current_segment += sentence
            else:
                if current_segment.strip():
                    segments.append(current_segment.strip())
                current_segment = sentence
        
        if current_segment.strip():
            segments.append(current_segment.strip())
        
        return segments
    
    def _smart_merge_segments(self, segments, merge_threshold, max_length):
        """智能合并过短的段落"""
        if not segments:
            return []
        
        merged = []
        current = segments[0]
        
        for i in range(1, len(segments)):
            next_segment = segments[i]
            
            if len(current) < merge_threshold:
                potential_length = len(current) + len(next_segment) + 2
                if potential_length <= max_length:
                    current += "\n\n" + next_segment
                    continue
            
            merged.append(current)
            current = next_segment
        
        merged.append(current)
        
        return [s.strip() for s in merged if s.strip()]
# 导入优化组件
try:
    from tts_optimizer import EnhancedTTSConverter
    HAS_TTS_OPTIMIZER = True
except ImportError:
    HAS_TTS_OPTIMIZER = False
    print("[警告] 未找到TTS优化器，将使用标准转换模式")

# 导入性能监控组件（可选）
try:
    from performance_monitor import PerformanceMonitorWidget
    HAS_PERFORMANCE_MONITOR = True
except ImportError:
    HAS_PERFORMANCE_MONITOR = False
    print("[警告] 未找到性能监控组件，将使用简化界面")

# 导入统一的线程池基类
try:
    from core.thread_pool_base import create_thread_pool, UnifiedSimpleThreadPool
    HAS_UNIFIED_POOL = True
    print("[信息] 找到统一线程池模块")
except ImportError:
    HAS_UNIFIED_POOL = False
    print("[警告] 统一线程池模块不可用，使用内置实现")

# 超级线程池实现 - 30万字专用
class SuperThreadPool:
    def __init__(self, max_workers=64, min_workers=16, text_length=0):
        import concurrent.futures
        import threading
        
        self.max_workers = max_workers
        self.min_workers = min_workers
        self.text_length = text_length
        
        # 动态调整线程数
        cpu_count = os.cpu_count() or 1
        if text_length > 500000:  # 50万字符以上
            optimal_workers = min(max_workers, cpu_count * 8)
        elif text_length > 300000:  # 30万字符以上
            optimal_workers = min(max_workers, cpu_count * 6)
        else:
            optimal_workers = min(max_workers, cpu_count * 4)
        
        self.current_workers = max(min_workers, optimal_workers)
        
        # 创建线程池
        self.executor = concurrent.futures.ThreadPoolExecutor(
            max_workers=self.current_workers,
            thread_name_prefix="SuperTTS-Worker"
        )
        
        # 性能监控
        self.completed_tasks = 0
        self.active_futures = set()
        self.lock = threading.Lock()
        self.start_time = time.time()
        
        print(f"线程池初始化: {self.current_workers} 个工作线程 (文本: {text_length:,} 字符)")
        
    def start(self):
        pass
        
    def submit_intelligent_task(self, func, text_length, task_id, task_type, *args, **kwargs):
        # 超级优化版本：最小化开销
        future = self.executor.submit(func, *args, **kwargs)
        
        with self.lock:
            self.active_futures.add(future)
        
        def super_callback(fut):
            with self.lock:
                self.active_futures.discard(fut)
                self.completed_tasks += 1
                
                # 每100个任务输出一次统计
                if self.completed_tasks % 100 == 0:
                    elapsed = time.time() - self.start_time
                    rate = self.completed_tasks / elapsed if elapsed > 0 else 0
                    print(f"⚡ 超级线程池: {self.completed_tasks} 任务完成 ({rate:.1f} 任务/秒)")
        
        future.add_done_callback(super_callback)
        return future
    
    def get_active_tasks(self):
        with self.lock:
            return len(self.active_futures)
    
    def reset_counters(self):
        """重置任务计数器"""
        with self.lock:
            self.completed_tasks = 0
            self.active_futures.clear()
    
    def get_performance_stats(self):
        """获取性能统计信息"""
        with self.lock:
            active_tasks = len(self.active_futures)
            completed = self.completed_tasks
        # 计算成功率（假设所有完成的任务都是成功的）
        success_rate = 100.0 if completed > 0 else 0.0
        return {
            'current_workers': self.current_workers,
            'active_tasks': active_tasks,
            'completed_tasks': completed,
            'success_rate': success_rate
        }
    
    def shutdown(self):
        if hasattr(self, 'executor'):
            self.executor.shutdown(wait=False)
            elapsed = time.time() - self.start_time
            print(f"🏁 超级线程池关闭: 总计 {self.completed_tasks} 任务，用时 {elapsed:.1f}秒")

# 优化线程池实现 - 标准大文本优化
class OptimizedThreadPool:
    def __init__(self, max_workers=32):
        import concurrent.futures
        import threading
        
        self.max_workers = max_workers
        self.current_workers = max_workers
        
        self.executor = concurrent.futures.ThreadPoolExecutor(
            max_workers=max_workers,
            thread_name_prefix="OptimizedTTS-Worker"
        )
        
        self.completed_tasks = 0
        self.active_futures = set()
        self.lock = threading.Lock()
        
    def start(self):
        pass
        
    def submit_intelligent_task(self, func, text_length, task_id, task_type, *args, **kwargs):
        future = self.executor.submit(func, *args, **kwargs)
        
        with self.lock:
            self.active_futures.add(future)
        
        def optimized_callback(fut):
            with self.lock:
                self.active_futures.discard(fut)
                self.completed_tasks += 1
        
        future.add_done_callback(optimized_callback)
        return future
    
    def get_active_tasks(self):
        with self.lock:
            return len(self.active_futures)
    
    def reset_counters(self):
        """重置任务计数器"""
        with self.lock:
            self.completed_tasks = 0
            self.active_futures.clear()
    
    def get_performance_stats(self):
        """获取性能统计信息"""
        with self.lock:
            active_tasks = len(self.active_futures)
            completed = self.completed_tasks
        # 计算成功率（假设所有完成的任务都是成功的）
        success_rate = 100.0 if completed > 0 else 0.0
        return {
            'current_workers': self.current_workers,
            'active_tasks': active_tasks,
            'completed_tasks': completed,
            'success_rate': success_rate
        }
    
    def shutdown(self):
        if hasattr(self, 'executor'):
            self.executor.shutdown(wait=False)

# 超级资源管理器 - 简化版，专注内存缓存
class SuperResourceManager:
    def __init__(self, text_length=0):
        self.text_length = text_length
        
        # 内存缓存配置
        if config_loader.is_mega_text(text_length):
            memory_config = config_loader.get_mega_text_config('memory')
            self.cache_size = memory_config.get('cache_size', 3 * 1024 * 1024 * 1024)  # 3GB
            self.in_memory_threshold = memory_config.get('in_memory_threshold', 10 * 1024 * 1024)  # 10MB
            print(f"🧠 超级资源管理器: {self.cache_size // (1024*1024*1024)}GB 内存缓存")
        else:
            self.cache_size = 512 * 1024 * 1024  # 512MB
            self.in_memory_threshold = 5 * 1024 * 1024  # 5MB
        
        # 内存缓存
        self.memory_cache = {}
        self.cache_usage = 0
        self.cache_lock = threading.Lock()
        
        # 临时文件追踪（简化：按需创建，自动清理）
        self.temp_files = []
        self.temp_files_lock = threading.Lock()
        
        # 垃圾回收优化
        self.gc_counter = 0
        self.gc_threshold = 100
        
    def get_temp_file(self):
        """创建临时文件（edge-tts输出MP3格式）"""
        try:
            temp_file = tempfile.NamedTemporaryFile(
                suffix='.mp3',  # edge-tts输出MP3格式
                delete=False,
                prefix='tts_'
            )
            temp_path = temp_file.name
            temp_file.close()
            
            with self.temp_files_lock:
                self.temp_files.append(temp_path)
            
            return temp_path
        except (OSError, IOError) as e:
            print(f"⚠️ 创建临时文件失败: {e}")
            raise
    
    def cache_audio_data(self, key, data):
        """缓存音频数据到内存"""
        if len(data) > self.in_memory_threshold:
            return False  # 太大不缓存
        
        with self.cache_lock:
            if self.cache_usage + len(data) > self.cache_size:
                self._cleanup_cache()
            
            if self.cache_usage + len(data) <= self.cache_size:
                self.memory_cache[key] = data
                self.cache_usage += len(data)
                return True
        return False
    
    def get_cached_audio_data(self, key):
        """从内存缓存获取音频数据"""
        with self.cache_lock:
            return self.memory_cache.get(key)
    
    def _cleanup_cache(self):
        """清理内存缓存 - LRU策略"""
        if not self.memory_cache:
            return
        
        # 简单的清理策略：删除一半缓存
        items_to_remove = len(self.memory_cache) // 2
        keys_to_remove = list(self.memory_cache.keys())[:items_to_remove]
        
        for key in keys_to_remove:
            data = self.memory_cache.pop(key, None)
            if data:
                self.cache_usage -= len(data)
        
        print(f"🧹 内存缓存清理: 删除 {items_to_remove} 项，剩余 {len(self.memory_cache)} 项")
    
    def optimize_gc(self):
        """优化垃圾回收"""
        self.gc_counter += 1
        if self.gc_counter >= self.gc_threshold:
            gc.collect()
            self.gc_counter = 0
    
    def cleanup_all(self):
        """清理所有资源"""
        # 清理内存缓存
        with self.cache_lock:
            self.memory_cache.clear()
            self.cache_usage = 0
        
        # 清理临时文件
        with self.temp_files_lock:
            for temp_file in self.temp_files:
                try:
                    if os.path.exists(temp_file):
                        os.unlink(temp_file)
                except (OSError, PermissionError, IOError) as e:
                    print(f"⚠️ 清理临时文件失败 {temp_file}: {e}")
            
            self.temp_files.clear()
        
        # 强制垃圾回收
        gc.collect()
        print("🧹 超级资源管理器: 所有资源已清理")

# 性能基准测试器
class PerformanceBenchmark:
    def __init__(self, text_length=0):
        self.text_length = text_length
        self.start_time = None
        self.end_time = None
        self.segment_count = 0
        self.thread_count = 0
        self.network_connections = 0
        self.memory_usage_mb = 0
        self.streaming_enabled = False
        
        # 性能指标
        self.total_time = 0
        self.segments_per_second = 0
        self.chars_per_second = 0
        self.speedup_ratio = 1.0
        
        # 基准数据（标准模式的预期性能）
        self.baseline_time_per_1k_chars = 2.0  # 秒/1000字符
        
    def start_benchmark(self, segment_count, thread_count, network_connections, streaming_enabled=False):
        """开始性能测试"""
        self.start_time = time.time()
        self.segment_count = segment_count
        self.thread_count = thread_count
        self.network_connections = network_connections
        self.streaming_enabled = streaming_enabled
        
        # 记录内存使用
        try:
            import psutil
            process = psutil.Process()
            self.memory_usage_mb = process.memory_info().rss / (1024 * 1024)
        except ImportError:
            self.memory_usage_mb = 0
        
        print(f"📊 性能测试开始:")
        print(f"   📝 文本长度: {self.text_length:,} 字符")
        print(f"   📄 段落数量: {segment_count}")
        print(f"   🧵 线程数量: {thread_count}")
        print(f"   🌐 网络连接: {network_connections}")
        print(f"   🌊 流式合并: {'启用' if streaming_enabled else '禁用'}")
        print(f"   💾 内存使用: {self.memory_usage_mb:.1f} MB")
    
    def end_benchmark(self):
        """结束性能测试并计算指标"""
        self.end_time = time.time()
        self.total_time = self.end_time - self.start_time
        
        # 计算性能指标
        if self.total_time > 0:
            self.segments_per_second = self.segment_count / self.total_time
            self.chars_per_second = self.text_length / self.total_time
            
            # 计算相对于基准的加速比
            baseline_time = (self.text_length / 1000) * self.baseline_time_per_1k_chars
            self.speedup_ratio = baseline_time / self.total_time if self.total_time > 0 else 1.0
        
        # 记录结束时内存使用
        try:
            import psutil
            process = psutil.Process()
            end_memory_mb = process.memory_info().rss / (1024 * 1024)
            memory_increase = end_memory_mb - self.memory_usage_mb
        except ImportError:
            memory_increase = 0
        
        # 输出性能报告
        print(f"\n🏆 性能测试完成:")
        print(f"   ⏱️  总用时: {self.total_time:.2f} 秒")
        print(f"   🚀 处理速度: {self.chars_per_second:,.0f} 字符/秒")
        print(f"   📊 段落速度: {self.segments_per_second:.1f} 段落/秒")
        print(f"   ⚡ 加速倍数: {self.speedup_ratio:.1f}x")
        print(f"   💾 内存增长: {memory_increase:+.1f} MB")
        
        # 性能等级评估
        if self.speedup_ratio >= 5.0:
            grade = "🏆 超级优化"
        elif self.speedup_ratio >= 3.0:
            grade = "🥇 优秀"
        elif self.speedup_ratio >= 2.0:
            grade = "🥈 良好"
        elif self.speedup_ratio >= 1.5:
            grade = "🥉 一般"
        else:
            grade = "⚠️ 需要优化"
        
        print(f"   📈 性能等级: {grade}")
        
        # 30万字专门评估
        if self.text_length >= 300000:
            target_time = 600  # 10分钟目标
            if self.total_time <= target_time:
                print(f"   🎯 30万字目标: ✅ 达成 (目标 {target_time//60}分钟)")
            else:
                remaining_time = self.total_time - target_time
                print(f"   🎯 30万字目标: ⏰ 超时 {remaining_time//60:.0f}分{remaining_time%60:.0f}秒")
        
        return {
            'total_time': self.total_time,
            'chars_per_second': self.chars_per_second,
            'segments_per_second': self.segments_per_second,
            'speedup_ratio': self.speedup_ratio,
            'memory_increase_mb': memory_increase,
            'grade': grade
        }

# 保留的简化线程池实现（兼容性）- 优化版本
class SimpleThreadPool:
    def __init__(self, max_workers=None):
        import concurrent.futures
        # 更智能的工作线程数计算
        cpu_count = os.cpu_count() or 1
        # 对于I/O密集型任务（如TTS），使用CPU核心数*2，但限制在合理范围内
        optimal_workers = min(max(2, cpu_count * 2), 16)
        self.max_workers = max_workers or optimal_workers
        self.executor = concurrent.futures.ThreadPoolExecutor(
            max_workers=self.max_workers,
            thread_name_prefix="TTS-Worker"
        )
        self.current_workers = self.max_workers
        self.completed_tasks = 0
        self.active_futures = set()  # 跟踪活跃的futures
        self.lock = threading.Lock()
        # 任务缓存，减少重复对象创建
        self._task_cache = {}
        self._cache_lock = threading.Lock()
        
    def start(self):
        pass
        
    def submit_intelligent_task(self, func, text_length, task_id, task_type, *args, **kwargs):
        # 优化版本：减少对象创建开销，优化回调处理
        future = self.executor.submit(func, *args, **kwargs)
        
        # 使用无锁操作减少竞争
        with self.lock:
            self.active_futures.add(future)
        
        # 优化的完成回调：批量处理，减少锁开销
        def optimized_callback(fut):
            with self.lock:
                self.active_futures.discard(fut)
                self.completed_tasks += 1
            # 清理任务缓存
            with self._cache_lock:
                self._task_cache.pop(task_id, None)
        
        future.add_done_callback(optimized_callback)
        return future
    
    def get_active_tasks(self):
        # 返回实际的活跃任务数
        with self.lock:
            # 清理已完成的futures
            self.active_futures = {f for f in self.active_futures if not f.done()}
            return len(self.active_futures)
    
    def get_performance_stats(self):
        active_tasks = self.get_active_tasks()
        return {
            'current_workers': self.current_workers,
            'active_tasks': active_tasks,
            'completed_tasks': self.completed_tasks,
            'success_rate': 100.0
        }
    
    def shutdown(self):
        self.executor.shutdown(wait=True)
        
    def reset_counters(self):
        with self.lock:
            self.completed_tasks = 0
            self.active_futures.clear()


class ConversionWorker(QThread):
    """后台转换线程"""
    progress = pyqtSignal(int)
    finished = pyqtSignal(bool, str)

    def __init__(self, text, output_file, voice, speed):
        super().__init__()
        self.text = text
        self.output_file = output_file
        self.voice = voice
        self.speed = speed
        
        # 实例级别的请求速率限制（避免多个转换任务之间的竞态条件）
        self.request_semaphore = threading.Semaphore(8)  # 最多8个并发请求
        self.last_request_time = 0
        self.request_lock = threading.Lock()
        
        # 超级智能线程池选择策略 - 支持30万字优化
        text_length = len(text)
        
        # 使用统一的配置加载器
        performance_mode = config_loader.auto_detect_performance_mode(text_length)
        
        if config_loader.is_mega_text(text_length):
            # 超大文本专用线程池配置
            concurrency_config = config_loader.get_mega_text_config('concurrency')
            max_workers = concurrency_config.get('max_workers', 64)
            min_workers = concurrency_config.get('min_workers', 16)
            print(f"🔥 超大文本检测: {text_length:,} 字符，启用 {max_workers} 线程超级并发")
            
            # 创建超级线程池
            self.thread_pool = SuperThreadPool(
                max_workers=max_workers,
                min_workers=min_workers,
                text_length=text_length
            )
            print(f"✅ 超级线程池已启用: {max_workers} 个工作线程")
        else:
            # 标准优化线程池
            optimal_workers = min(max(8, os.cpu_count() * 4), 32)  # 提升到32线程
            self.thread_pool = OptimizedThreadPool(max_workers=optimal_workers)
            print(f"📈 优化线程池已启用: {optimal_workers} 个工作线程")
        
        # 如果配置不可用，回退策略
        if not config_loader.is_available():
            
            # 回退策略 - 但仍然优化
            if HAS_UNIFIED_POOL:
                self.thread_pool = create_thread_pool('auto')
                print("[信息] 使用统一线程池 (UnifiedSimpleThreadPool)")
            else:
                try:
                    from thread_pool import IntelligentThreadPool
                    self.thread_pool = IntelligentThreadPool()
                    print("[信息] 使用智能线程池 (IntelligentThreadPool)")
                except ImportError:
                    # 即使是简化线程池也要优化
                    optimal_workers = min(max(8, os.cpu_count() * 2), 24)
                    self.thread_pool = SimpleThreadPool(max_workers=optimal_workers)
                    print(f"[优化] 使用简化线程池: {optimal_workers} 个工作线程")
            
        self.segment_results = {}
        self._stop_flag = False
        self.actual_segments_count = 0  # 保存实际使用的分段数
        
        # 初始化超级资源管理器
        self.resource_manager = SuperResourceManager(text_length=text_length)
        print(f"🎯 资源管理器已启用: {text_length:,} 字符文本")
        
        # 初始化性能基准测试器
        self.benchmark = PerformanceBenchmark(text_length=text_length)

    def stop(self):
        """停止转换任务"""
        self._stop_flag = True
        if hasattr(self, 'thread_pool'):
            self.thread_pool.shutdown()
        if hasattr(self, 'resource_manager'):
            self.resource_manager.cleanup_all()

    def split_text(self, text, max_length=1000, min_length=100):
        """文本分割 - 使用统一的TextSegmenter"""
        segmenter = TextSegmenter(text_length=len(text))
        return segmenter.split_text(text, max_length, min_length)
    
    def _init_streaming_merger(self, output_file, total_segments):
        """初始化流式音频合并器（支持MP3格式）"""
        if hasattr(self, 'text') and config_loader.is_mega_text(len(self.text)):
            streaming_config = config_loader.get_mega_text_config('streaming')
            self.streaming_enabled = streaming_config.get('enable_streaming_merge', True)
            self.merge_chunk_size = streaming_config.get('merge_chunk_size', 2 * 1024 * 1024)
            self.concurrent_mergers = streaming_config.get('concurrent_mergers', 4)
            print(f"🌊 流式合并已启用: {self.merge_chunk_size // (1024*1024)}MB 块大小")
        else:
            self.streaming_enabled = False
        
        if self.streaming_enabled:
            # 初始化流式合并状态（MP3直接拼接）
            self.output_file_path = output_file
            self.output_file_handle = open(output_file, 'wb')  # 直接打开输出文件
            self.completed_segments = [False] * total_segments
            self.segment_data_cache = {}
            self.next_merge_index = 0
            self.merge_lock = threading.Lock()
            print(f"🎵 流式合并器初始化完成: {total_segments} 个段落")
    
    def _stream_merge_segment(self, segment_index, audio_file_path):
        """流式合并单个音频段落（MP3直接拼接）"""
        if not self.streaming_enabled:
            return
        
        try:
            with self.merge_lock:
                # 缓存音频文件路径（而不是数据，减少内存占用）
                self.segment_data_cache[segment_index] = audio_file_path
                self.completed_segments[segment_index] = True
                
                # 尝试合并连续的已完成段落
                while (self.next_merge_index < len(self.completed_segments) and 
                       self.completed_segments[self.next_merge_index]):
                    
                    # 处理下一个连续段落
                    if self.next_merge_index in self.segment_data_cache:
                        temp_file = self.segment_data_cache.pop(self.next_merge_index)
                        
                        try:
                            # MP3可以直接拼接，无需特殊处理
                            with open(temp_file, 'rb') as infile:
                                # 分块读取并写入
                                CHUNK_SIZE = 1024 * 1024  # 1MB chunks
                                while True:
                                    chunk = infile.read(CHUNK_SIZE)
                                    if not chunk:
                                        break
                                    self.output_file_handle.write(chunk)
                                
                                # 确保数据写入磁盘
                                self.output_file_handle.flush()
                                
                        except Exception as e:
                            print(f"⚠️ 流式写入段落 {self.next_merge_index} 失败: {e}")
                        
                        # 优化垃圾回收
                        if hasattr(self, 'resource_manager'):
                            self.resource_manager.optimize_gc()
                    
                    self.next_merge_index += 1
                
                # 计算合并进度（每10个段落输出一次）
                if self.next_merge_index % 10 == 0 or self.next_merge_index == 1:
                    merge_progress = (self.next_merge_index / len(self.completed_segments)) * 100
                    print(f"🌊 流式合并进度: {self.next_merge_index}/{len(self.completed_segments)} "
                          f"({merge_progress:.1f}%)")
                
        except Exception as e:
            print(f"⚠️ 流式合并段落 {segment_index} 失败: {e}")
    
    def _finalize_streaming_merge(self):
        """完成流式合并（关闭MP3文件）"""
        if not self.streaming_enabled:
            return True
        
        try:
            with self.merge_lock:
                # 确保所有剩余段落都已写入
                for i in range(self.next_merge_index, len(self.completed_segments)):
                    if i in self.segment_data_cache:
                        temp_file = self.segment_data_cache.pop(i)
                        try:
                            # MP3直接拼接
                            with open(temp_file, 'rb') as infile:
                                CHUNK_SIZE = 1024 * 1024  # 1MB chunks
                                while True:
                                    chunk = infile.read(CHUNK_SIZE)
                                    if not chunk:
                                        break
                                    self.output_file_handle.write(chunk)
                        except Exception as e:
                            print(f"⚠️ 完成合并时写入段落 {i} 失败: {e}")
                
                # 关闭输出文件
                if self.output_file_handle:
                    self.output_file_handle.close()
                    print("🎵 流式合并完成（MP3文件已正确关闭）")
                else:
                    print("⚠️ 流式合并：没有音频数据被写入")
                    return False
                    
                return True
                
        except Exception as e:
            print(f"❌ 流式合并完成时出错: {e}")
            # 尝试关闭文件句柄
            if hasattr(self, 'output_file_handle') and self.output_file_handle:
                try:
                    self.output_file_handle.close()
                except:
                    pass
            return False

    async def _async_convert(self, segment_text, temp_file, voice, rate, segment_index):
        """异步转换单个段落（提取的异步逻辑）"""
        session = None
        
        try:
            # 动态网络配置 - 根据文本大小调整
            text_length = len(segment_text)
            if hasattr(self, 'text') and config_loader.is_mega_text(len(self.text)):
                # 超大文本模式 - 优化网络配置
                network_config = config_loader.get_mega_text_config('network')
                total_timeout = 300  # 5分钟
                connect_timeout = 15  # 15秒连接
                total_connections = network_config.get('total_connections', 12)
                connections_per_host = network_config.get('connections_per_host', 6)
                keepalive_timeout = network_config.get('keepalive_timeout', 60)
                retry_attempts = network_config.get('retry_attempts', 3)
                retry_delay = network_config.get('retry_delay', 2.0)
                rate_limit_delay = network_config.get('rate_limit_delay', 0.5)
                print(f"🚀 段落{segment_index + 1}: 启用超级网络模式 ({total_connections}连接)")
            else:
                # 标准优化配置
                total_timeout = 180
                connect_timeout = 30
                total_connections = 8
                connections_per_host = 4
                keepalive_timeout = 30
                retry_attempts = 3
                retry_delay = 1.5
                rate_limit_delay = 0.3
            
            # 高性能连接配置
            timeout = aiohttp.ClientTimeout(
                total=total_timeout, 
                connect=connect_timeout,
                sock_read=60
            )
            
            connector = aiohttp.TCPConnector(
                limit=total_connections,
                limit_per_host=connections_per_host,
                enable_cleanup_closed=True,
                force_close=False,
                keepalive_timeout=keepalive_timeout,
                use_dns_cache=True,
                ttl_dns_cache=300,
                family=socket.AF_INET,
                ssl=False
            )
            
            session = aiohttp.ClientSession(
                connector=connector, 
                timeout=timeout,
                headers={
                    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
                    'Connection': 'keep-alive',
                    'Accept-Encoding': 'gzip, deflate'
                }
            )
            
            # 带重试机制的转换
            last_error = None
            for attempt in range(retry_attempts):
                try:
                    # 获取请求许可（实例级速率限制）
                    with self.request_semaphore:
                        # 添加请求间隔避免过于频繁
                        if attempt > 0:
                            await asyncio.sleep(retry_delay * attempt)
                        
                        # 实例级请求间隔控制
                        with self.request_lock:
                            current_time = time.time()
                            time_since_last = current_time - self.last_request_time
                            if time_since_last < rate_limit_delay:
                                await asyncio.sleep(rate_limit_delay - time_since_last)
                            self.last_request_time = time.time()
                        
                        # 转换文本段
                        communicate = edge_tts.Communicate(
                            text=segment_text,
                            voice=voice,
                            rate=rate
                        )
                        communicate.session = session
                        await communicate.save(temp_file)
                        
                        # 验证文件是否成功创建
                        if os.path.exists(temp_file) and os.path.getsize(temp_file) > 0:
                            return segment_index, temp_file
                        else:
                            raise IOError("生成的音频文件为空或不存在")
                        
                except (aiohttp.ClientError, asyncio.TimeoutError) as e:
                    last_error = e
                    error_msg = str(e)
                    
                    # 网络错误，可以重试
                    print(f"⚠️ 段落{segment_index + 1}第{attempt + 1}次尝试失败: {error_msg}")
                    if attempt < retry_attempts - 1:
                        print(f"🔄 段落{segment_index + 1}将在{retry_delay * (attempt + 1):.1f}秒后重试...")
                        continue
                except (IOError, OSError) as e:
                    last_error = e
                    error_msg = str(e)
                    
                    # 文件IO错误，可以重试
                    if "No audio was received" in error_msg:
                        print(f"⚠️ 段落{segment_index + 1}第{attempt + 1}次尝试失败: {error_msg}")
                        if attempt < retry_attempts - 1:
                            print(f"🔄 段落{segment_index + 1}将在{retry_delay * (attempt + 1):.1f}秒后重试...")
                            continue
                    # 其他IO错误直接抛出
                    raise
                except Exception as e:
                    # 未预期的错误，直接抛出
                    print(f"❌ 段落{segment_index + 1}发生未预期错误: {type(e).__name__}: {e}")
                    raise
            
            # 所有重试都失败了
            raise last_error
                
        except (aiohttp.ClientError, asyncio.TimeoutError, IOError, OSError) as async_e:
            error_msg = str(async_e)
            print(f"❌ 段落{segment_index + 1}转换错误: {error_msg}")
            raise
            
        finally:
            # 简化的资源清理
            if session and not session.closed:
                await session.close()
            # 短暂等待确保清理完成
            await asyncio.sleep(0.05)
    
    def convert_single_segment(self, segment_data):
        """转换单个文本段落（优化版 - 使用asyncio.run()）"""
        segment_text, segment_index, temp_file, voice, rate = segment_data
        
        try:
            # 使用asyncio.run()自动管理event loop生命周期
            result = asyncio.run(
                self._async_convert(segment_text, temp_file, voice, rate, segment_index)
            )
            return True, result
        except (aiohttp.ClientError, asyncio.TimeoutError) as e:
            # 网络错误
            error_detail = f"段落{segment_index + 1}网络错误: {type(e).__name__}: {str(e)}"
            print(f"❌ {error_detail}")
            return False, (segment_index, str(e))
        except (IOError, OSError) as e:
            # 文件IO错误
            error_detail = f"段落{segment_index + 1}文件错误: {type(e).__name__}: {str(e)}"
            print(f"❌ {error_detail}")
            return False, (segment_index, str(e))
        except Exception as e:
            # 其他未预期错误
            import traceback
            error_detail = f"段落{segment_index + 1}转换失败: {type(e).__name__}: {str(e)}\n详细信息: {traceback.format_exc()[-500:]}"
            print(f"❌ {error_detail}")
            return False, (segment_index, str(e))

    def run(self):
        """使用智能线程池进行并行转换"""
        try:
            if self._stop_flag:
                self.finished.emit(False, "转换已取消")
                return
                
            if not self.text or self.text.isspace():
                self.finished.emit(False, "文本内容不能为空")
                return

            # 重置任务计数器
            self.thread_pool.reset_counters()
            
            # 初始化进度
            self.progress.emit(5)
            
            # 设置语速
            if self.speed < 1.0:
                rate = f"{int((self.speed - 1.0) * 100)}%"
            elif self.speed > 1.0:
                rate = f"+{int((self.speed - 1.0) * 100)}%"
            else:
                rate = "+0%"

            # 智能分割文本，根据文本长度自适应调整分段策略
            text_length = len(self.text)
            if text_length < 500:
                # 短文本：不分割或按自然段落分割
                text_segments = self.split_text(self.text, max_length=1000, min_length=500)
            elif text_length < 3000:
                # 中等文本：适中分割以充分利用并行
                text_segments = self.split_text(self.text, max_length=800, min_length=200)
            else:
                # 长文本：积极分割以最大化并行效率
                text_segments = self.split_text(self.text, max_length=600, min_length=150)
            total_segments = len(text_segments)
            self.actual_segments_count = total_segments  # 保存实际分段数
            
            self.progress.emit(10)

            # 使用超级资源管理器创建临时文件
            temp_files = []
            for i in range(total_segments):
                temp_file = self.resource_manager.get_temp_file()
                temp_files.append(temp_file)
            
            print(f"📁 临时文件分配完成: {len(temp_files)} 个文件")
            
            # 初始化流式合并器
            self._init_streaming_merger(self.output_file, total_segments)
            
            # 开始性能基准测试
            thread_count = getattr(self.thread_pool, 'current_workers', 16)
            network_connections = 30 if hasattr(self, 'streaming_enabled') and self.streaming_enabled else 15
            self.benchmark.start_benchmark(
                segment_count=total_segments,
                thread_count=thread_count,
                network_connections=network_connections,
                streaming_enabled=getattr(self, 'streaming_enabled', False)
            )

            try:
                # 启动线程池
                self.thread_pool.start()
                
                # 准备任务数据
                segment_tasks = []
                for i, segment in enumerate(text_segments):
                    task_data = (segment, i, temp_files[i], self.voice, rate)
                    segment_tasks.append(task_data)
                
                # 智能并行提交所有任务
                print(f"[开始] 开始智能并行转换 {total_segments} 个段落...")
                print(f"[统计] 智能线程池状态: 初始工作线程数 = {self.thread_pool.current_workers}")
                futures = []
                for task_data in segment_tasks:
                    segment_text, segment_index, temp_file, voice, rate = task_data
                    task_id = f"segment_{segment_index}"
                    text_len = len(segment_text)
                    print(f"[提交] 提交段落{segment_index + 1}: {text_len}字符 -> {temp_file}")
                    
                    # 使用智能任务提交
                    future = self.thread_pool.submit_intelligent_task(
                        self.convert_single_segment, 
                        text_len,  # text_length作为位置参数
                        task_id,   # task_id作为位置参数
                        "tts",     # task_type作为位置参数
                        task_data  # segment_data作为单个参数传递
                    )
                    futures.append(future)
                
                # 等待任务完成并收集结果（支持重试机制）
                completed_count = 0
                failed_tasks = []  # 记录失败的任务信息 (segment_index, task_data, error)
                segment_files = {}  # 使用字典保存段落索引到文件的映射 {segment_index: temp_file}
                task_results = {}  # 记录任务结果 {segment_index: (success, result)}
                
                for future in concurrent.futures.as_completed(futures):
                    if self._stop_flag:
                        self.finished.emit(False, "转换已取消")
                        return
                        
                    try:
                        success, result = future.result()
                        completed_count += 1
                        
                        # 更新进度（15-75%，为重试留10%空间）
                        progress = 15 + (completed_count * 60 // total_segments)
                        self.progress.emit(progress)
                        
                        if success:
                            segment_index, temp_file = result
                            task_results[segment_index] = (True, temp_file)
                            if os.path.exists(temp_file):
                                segment_files[segment_index] = temp_file  # 使用segment_index作为键
                                # 流式合并：立即合并完成的段落
                                self._stream_merge_segment(segment_index, temp_file)
                            else:
                                # 文件未生成，准备重试
                                task_data = segment_tasks[segment_index]
                                failed_tasks.append((segment_index, task_data, "音频文件未生成"))
                        else:
                            segment_index, error = result
                            task_results[segment_index] = (False, error)
                            task_data = segment_tasks[segment_index]
                            failed_tasks.append((segment_index, task_data, error))
                            
                    except Exception as e:
                        # 无法确定段落索引，先记录错误
                        print(f"[错误] 任务执行异常: {str(e)}")
                
                # 重试失败的任务（最多3次）
                retry_count = 0
                max_retries = 3
                
                while failed_tasks and retry_count < max_retries:
                    retry_count += 1
                    print(f"[重试] 第{retry_count}次重试，重试{len(failed_tasks)}个失败段落...")
                    
                    current_failed_tasks = failed_tasks.copy()
                    failed_tasks = []
                    retry_futures = []
                    
                    # 重新提交失败的任务
                    for segment_index, task_data, error in current_failed_tasks:
                        if self._stop_flag:
                            self.finished.emit(False, "转换已取消")
                            return
                            
                        segment_text, _, temp_file, voice, rate = task_data
                        task_id = f"retry_{retry_count}_segment_{segment_index}"
                        text_len = len(segment_text)
                        print(f"[重试] 重试段落{segment_index + 1}: {text_len}字符")
                        
                        future = self.thread_pool.submit_intelligent_task(
                            self.convert_single_segment,
                            text_len,
                            task_id,
                            "tts_retry",
                            task_data
                        )
                        retry_futures.append((future, segment_index, task_data))
                    
                    # 等待重试任务完成
                    retry_completed = 0
                    for future, segment_index, task_data in retry_futures:
                        if self._stop_flag:
                            self.finished.emit(False, "转换已取消")
                            return
                            
                        try:
                            success, result = future.result()
                            retry_completed += 1
                            
                            # 更新重试进度（75-85%）
                            retry_progress = 75 + (retry_completed * 10 // len(retry_futures))
                            self.progress.emit(retry_progress)
                            
                            if success:
                                segment_index_result, temp_file = result
                                task_results[segment_index] = (True, temp_file)
                                if os.path.exists(temp_file):
                                    # 从失败列表中移除，添加到segment_files字典
                                    segment_files[segment_index] = temp_file
                                    print(f"[成功] 段落{segment_index + 1}重试成功")
                                else:
                                    failed_tasks.append((segment_index, task_data, "重试后音频文件仍未生成"))
                            else:
                                segment_index_result, error = result
                                task_results[segment_index] = (False, error)
                                failed_tasks.append((segment_index, task_data, f"重试失败: {error}"))
                                
                        except Exception as e:
                            failed_tasks.append((segment_index, task_data, f"重试异常: {str(e)}"))
                    
                    if not failed_tasks:
                        print(f"🎉 所有段落在第{retry_count}次重试后成功!")
                        break
                    else:
                        print(f"[警告] 第{retry_count}次重试后仍有{len(failed_tasks)}个段落失败")
                
                # 统计最终结果
                success_count = len(segment_files)
                total_count = total_segments
                final_failed_segments = [f"段落{idx + 1}: {error}" for idx, _, error in failed_tasks]
                
                if success_count == 0:
                    # 所有段落都失败了
                    error_msg = f"所有段落转换失败（重试{max_retries}次后）:\n" + "\n".join(final_failed_segments[:5])
                    if len(final_failed_segments) > 5:
                        error_msg += f"\n...还有{len(final_failed_segments) - 5}个错误"
                    self.finished.emit(False, error_msg)
                    return
                elif final_failed_segments:
                    # 部分段落失败，但仍有成功的，显示警告但继续
                    print(f"[警告] 经过{retry_count}次重试后，仍有部分段落转换失败 ({len(final_failed_segments)}/{total_count}):") 
                    for error in final_failed_segments[:3]:  # 只打印前3个错误
                        print(f"   {error}")
                    if len(final_failed_segments) > 3:
                        print(f"   ...还有{len(final_failed_segments) - 3}个错误")
                    print(f"[成功] 成功转换 {success_count}/{total_count} 个段落，继续合并...")
                else:
                    retry_msg = f"（经过{retry_count}次重试）" if retry_count > 0 else ""
                    print(f"[成功] 所有 {total_count} 个段落转换成功{retry_msg}")
                
                # 检查是否需要停止
                if self._stop_flag:
                    self.finished.emit(False, "转换已取消")
                    return
                
                # 完成音频合并
                self.progress.emit(85)
                try:
                    if self.streaming_enabled:
                        # 流式合并：完成剩余合并
                        merge_success = self._finalize_streaming_merge()
                        if not merge_success:
                            raise Exception("流式合并失败")
                        print("🎵 流式合并模式：音频文件已实时合并完成")
                    elif segment_files:
                        # 传统合并模式：按segment_index排序生成有序文件列表
                        sorted_files = [segment_files[i] for i in sorted(segment_files.keys())]
                        self.merge_audio_files(sorted_files, self.output_file)
                        print("📁 传统合并模式：音频文件合并完成")
                        
                        # 完成消息
                        self.progress.emit(100)
                        
                        # 结束性能基准测试
                        benchmark_results = self.benchmark.end_benchmark()
                        
                        if final_failed_segments:
                            # 部分成功
                            # 获取性能统计
                            perf_stats = self.thread_pool.get_performance_stats()
                            
                            retry_info = f"（经过{retry_count}次重试）" if retry_count > 0 else ""
                            success_msg = f"[成功] 智能转换完成（部分成功）{retry_info}！\n"
                            success_msg += f"成功处理了 {success_count}/{total_count} 个分段\n"
                            success_msg += f"智能线程数调整: {perf_stats['current_workers']} 个工作线程\n"
                            success_msg += f"成功率: {perf_stats['success_rate']:.1f}%\n"
                            success_msg += f"[警告] {len(final_failed_segments)} 个段落最终转换失败"
                            self.finished.emit(True, success_msg)
                        else:
                            # 完全成功
                            # 获取性能统计
                            perf_stats = self.thread_pool.get_performance_stats()
                            
                            retry_info = f"（经过{retry_count}次重试）" if retry_count > 0 else ""
                            success_msg = f"[成功] 智能转换完成{retry_info}！\n"
                            success_msg += f"并行处理了 {total_segments} 个分段\n"
                            success_msg += f"智能线程数调整: {perf_stats['current_workers']} 个工作线程\n"
                            success_msg += f"成功率: {perf_stats['success_rate']:.1f}%"
                            
                            # 计算正确的平均段处理时间：总时间/总段数
                            if hasattr(self, 'conversion_start_time'):
                                total_time = time.time() - self.conversion_start_time
                                avg_per_segment = total_time / max(1, total_segments)
                                success_msg += f"\n平均段处理时间: {avg_per_segment:.0f}秒"
                                
                            self.finished.emit(True, success_msg)
                    else:
                        self.finished.emit(False, "没有成功转换的音频文件可供合并")
                        return
                except Exception as e:
                    self.finished.emit(False, f"音频合并失败: {str(e)}")
                    return

            finally:
                # 关闭线程池
                self.thread_pool.shutdown()
                
                # 优化的临时文件清理 - 使用资源管理器
                self._cleanup_temp_files(temp_files)

        except Exception as e:
            error_msg = str(e)
            if "No audio was received" in error_msg:
                self.finished.emit(False, "未能获取到语音，请尝试更换语音或重试")
            elif "Connection error" in error_msg:
                self.finished.emit(False, "网络连接错误，请检查网络设置")
            elif "SSLError" in error_msg:
                self.finished.emit(False, "SSL证书验证失败，请检查网络设置")
            else:
                self.finished.emit(False, f"转换失败: {error_msg}")

    def _cleanup_temp_files(self, temp_files):
        """优化的临时文件清理 - 使用资源管理器"""
        try:
            # 使用资源管理器清理
            if hasattr(self, 'resource_manager'):
                try:
                    self.resource_manager.cleanup_all()
                    return
                except (OSError, PermissionError, IOError) as e:
                    print(f"⚠️ 资源管理器清理失败: {e}")
                    # 继续使用传统方式清理
            
            # 回退到传统清理方式
            for temp_file in temp_files:
                try:
                    if os.path.exists(temp_file):
                        os.unlink(temp_file)
                except (OSError, PermissionError) as e:
                    print(f"⚠️ 无法删除临时文件 {os.path.basename(temp_file)}: {e}")
                except Exception as e:
                    print(f"⚠️ 删除临时文件时发生意外错误 {os.path.basename(temp_file)}: {e}")
            
        except Exception as e:
            print(f"⚠️ 临时文件清理失败（未预期的错误）: {e}")

    def merge_audio_files(self, temp_files, output_file):
        """合并多个音频文件"""
        return self._merge_with_simple_concat(temp_files, output_file)
    

    def _merge_with_simple_concat(self, temp_files, output_file):
        """合并MP3音频文件（简单二进制拼接）"""
        print("[合并] 使用MP3合并模式合并音频文件")
        
        # 检查有效文件（temp_files已经是按segment_index排序的列表）
        valid_files = []
        missing_files = []
        
        for temp_file in temp_files:
            if os.path.exists(temp_file):
                valid_files.append(temp_file)
            else:
                missing_files.append(os.path.basename(temp_file))
        
        if missing_files:
            print(f"[警告] 以下文件不存在，将跳过: {', '.join(missing_files[:5])}")
            if len(missing_files) > 5:
                print(f"   ...还有{len(missing_files) - 5}个文件不存在")
        
        if len(valid_files) == 0:
            raise Exception("没有有效的音频文件可供合并")
        elif len(valid_files) == 1:
            import shutil
            shutil.copy2(valid_files[0], output_file)
            print(f"[完成] 单文件直接复制到 {os.path.basename(output_file)}")
            return
        
        # MP3文件可以直接拼接（简单高效）
        print(f"[合并] 开始合并 {len(valid_files)} 个MP3文件...")
        try:
            CHUNK_SIZE = 1024 * 1024  # 1MB chunks for better performance
            
            with open(output_file, 'wb') as outfile:
                for i, temp_file in enumerate(valid_files, start=1):
                    try:
                        with open(temp_file, 'rb') as infile:
                            # MP3可以直接拼接，不需要跳过header
                            while True:
                                chunk = infile.read(CHUNK_SIZE)
                                if not chunk:
                                    break
                                outfile.write(chunk)
                        
                        # 每10个文件或最后一个文件时输出进度
                        if i % 10 == 0 or i == len(valid_files):
                            print(f"   [进度] 已合并 {i}/{len(valid_files)} 个文件")
                            
                    except Exception as e:
                        print(f"   [警告] 合并文件 {os.path.basename(temp_file)} 时出错: {e}")
                        continue
            
            print(f"[完成] 已成功合并 {len(valid_files)}/{len(temp_files)} 个MP3文件到 {os.path.basename(output_file)}")
            
        except Exception as e:
            print(f"[错误] MP3合并失败: {e}")
            raise
    
    def _merge_with_binary_fallback(self, valid_files, output_file):
        """回退方案：MP3文件直接拼接（此方法现在与主方法相同）"""
        print("[合并] 使用回退拼接模式...")
        CHUNK_SIZE = 64 * 1024
        
        with open(output_file, 'wb') as outfile:
            for i, temp_file in enumerate(valid_files):
                try:
                    with open(temp_file, 'rb') as infile:
                        # MP3可以直接拼接，无需特殊处理
                        while True:
                            chunk = infile.read(CHUNK_SIZE)
                            if not chunk:
                                break
                            outfile.write(chunk)
                        print(f"   [进度] 已拼接第 {i+1} 个文件: {os.path.basename(temp_file)}")
                except Exception as e:
                    print(f"   [警告] 拼接文件 {os.path.basename(temp_file)} 时出错: {e}")
                    continue
        
        print(f"[完成] 已拼接 {len(valid_files)} 个MP3文件（回退模式）")


class TextToSpeechApp(QMainWindow):
    

        
    def closeEvent(self, event):
        """处理窗口关闭事件，确保资源正确清理"""
        try:
            # 停止转换工作线程
            if hasattr(self, 'worker') and self.worker and self.worker.isRunning():
                print("🛑 正在停止转换任务...")
                self.worker.stop()
                self.worker.wait(3000)  # 等待最多3秒
                if self.worker.isRunning():
                    self.worker.terminate()
                    self.worker.wait(1000)
            
            # 清理其他资源
            if hasattr(self, 'timer'):
                self.timer.stop()
                
            print("[完成] 资源清理完成")
            event.accept()
            
        except Exception as e:
            print(f"[警告] 关闭时清理资源出错: {e}")
            event.accept()  # 仍然接受关闭事件
    
    def __init__(self):
        super().__init__()
        self.setWindowTitle("文字转语音工具")
        self.setMinimumSize(1200, 900)  # 增加窗口最小尺寸以容纳所有内容
        self.resize(1300, 950)  # 设置默认窗口尺寸
        
        # 智能分段配置 - 根据CPU核心数动态调整
        self.cpu_cores = multiprocessing.cpu_count()
        self.recommended_threads = min(max(2, self.cpu_cores * 2), 16)
        print(f"[系统] 检测到 {self.cpu_cores} 个CPU核心，推荐使用 {self.recommended_threads} 个线程")
        
        # 初始化完成
        print("[信息] 应用初始化完成")
        self.setStyleSheet("""
            QMainWindow {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                           stop:0 #f8fafc, stop:1 #e2e8f0);
                font-family: 'Microsoft YaHei', 'Segoe UI', Arial, sans-serif;
            }
            QLabel {
                color: #1e293b;
                font-size: 14px;
                font-weight: 500;
                margin: 5px 0;
            }
            QTextEdit {
                border: 2px solid #e2e8f0;
                border-radius: 16px;
                padding: 20px;
                background-color: #ffffff;
                font-size: 14px;
                color: #334155;
                selection-background-color: #3b82f6;
                selection-color: white;
                min-height: 160px;
            }
            QTextEdit:focus {
                border-color: #3b82f6;
                background-color: #f8fafc;
            }
            QTextEdit:hover {
                border-color: #94a3b8;
            }
            QPushButton {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                           stop:0 #3b82f6, stop:1 #2563eb);
                color: white;
                border: none;
                border-radius: 12px;
                padding: 14px 28px;
                font-size: 14px;
                font-weight: 600;
                min-width: 140px;
                margin: 8px;
            }
            QPushButton:hover {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                           stop:0 #2563eb, stop:1 #1d4ed8);
            }
            QPushButton:pressed {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                           stop:0 #1d4ed8, stop:1 #1e40af);
            }
            QComboBox {
                border: 2px solid #e2e8f0;
                border-radius: 12px;
                padding: 12px 16px;
                background-color: #ffffff;
                font-size: 14px;
                color: #334155;
                min-width: 220px;
                margin: 5px 0;
            }
            QComboBox:hover {
                border-color: #3b82f6;
            }
            QComboBox:focus {
                border-color: #3b82f6;
            }
            QComboBox::drop-down {
                border: none;
                width: 30px;
            }
            QComboBox::down-arrow {
                image: none;
                border-left: 6px solid transparent;
                border-right: 6px solid transparent;
                border-top: 6px solid #2c3e50;
                margin-right: 15px;
            }
            QComboBox:on {
                border-color: #3498db;
            }
            QComboBox QAbstractItemView {
                border: 1px solid #e8e8e8;
                background-color: #ffffff;
                color: #2c3e50;
                selection-background-color: #3498db;
                selection-color: white;
                padding: 5px;
                margin: 0px;
                border-radius: 0px;
                outline: none;
            }
            QComboBox QAbstractItemView::item {
                height: 30px;
                padding: 5px;
                border: none;
            }
            QComboBox QAbstractItemView::item:hover {
                background-color: #f5f5f5;
            }
            QComboBox QAbstractItemView::item:selected {
                background-color: #3498db;
                color: white;
            }
            QProgressBar {
                border: none;
                border-radius: 10px;
                text-align: center;
                background-color: #f0f0f0;
                color: #ffffff;
                font-weight: bold;
                height: 20px;
                margin: 10px 0;
            }
            QProgressBar::chunk {
                background-color: #3498db;
                border-radius: 10px;
            }
            QSlider::groove:horizontal {
                border: none;
                height: 8px;
                background: #e8e8e8;
                border-radius: 4px;
                margin: 2px 0;
            }
            QSlider::handle:horizontal {
                background: #3498db;
                border: none;
                width: 18px;
                height: 18px;
                margin: -5px 0;
                border-radius: 9px;
            }
            QSlider::handle:horizontal:hover {
                background: #2980b9;
            }
            QSlider::sub-page:horizontal {
                background: #3498db;
                border-radius: 4px;
            }
            QSlider::add-page:horizontal {
                background: #e8e8e8;
                border-radius: 4px;
            }
        """)

        # 创建语音映射字典 - 包含所有可用的中文语音
        self.voice_mapping = {
            # 中国大陆普通话（推荐-最快速度）
            "晓晓（女声-标准）": "zh-CN-XiaoxiaoNeural",
            "云希（男声-标准）": "zh-CN-YunxiNeural",
            "晓伊（女声-温柔）": "zh-CN-XiaoyiNeural", 
            "云扬（男声-新闻）": "zh-CN-YunyangNeural",
            "云健（男声-活力）": "zh-CN-YunjianNeural",
            "云霞（男声-深沉）": "zh-CN-YunxiaNeural",
            
            # 中国台湾地区（较慢）
            "🌏 晓陈（女声-台湾）": "zh-TW-HsiaoChenNeural",
            "🌏 晓宇（女声-台湾）": "zh-TW-HsiaoYuNeural",
            "🌏 云哲（男声-台湾）": "zh-TW-YunJheNeural",
            
            # 中国香港地区（较慢）
            "🌏 晓佳（女声-粤语）": "zh-HK-HiuGaaiNeural",
            "🌏 晓雯（女声-港音）": "zh-HK-HiuMaanNeural",
            "🌏 云龙（男声-港音）": "zh-HK-WanLungNeural",
            
            # 方言版本（较慢）
            "🎭 晓贝（女声-东北）": "zh-CN-liaoning-XiaobeiNeural",
            "🎭 晓妮（女声-陕西）": "zh-CN-shaanxi-XiaoniNeural",
        }

        self.setup_ui()

    def setup_ui(self):
        # 创建中央部件和主布局 - 水平分栏布局
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QHBoxLayout(central_widget)
        main_layout.setContentsMargins(15, 15, 15, 15)
        main_layout.setSpacing(15)
        
        # 创建左侧主要功能区域
        left_widget = QWidget()
        left_widget.setMinimumWidth(600)  # 设置左侧面板最小宽度为600px（增加200px）
        left_layout = QVBoxLayout(left_widget)
        left_layout.setContentsMargins(20, 15, 20, 20)
        left_layout.setSpacing(15)

        # 标题
        title_label = QLabel("文字转语音工具")
        title_label.setAlignment(Qt.AlignCenter)
        title_label.setStyleSheet("""
            font-size: 32px;
            color: #3b82f6;
            font-weight: 700;
            margin: 15px 0 25px 0;
            padding: 15px;
            border-radius: 12px;
            background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                       stop:0 rgba(59, 130, 246, 0.1), stop:1 rgba(139, 92, 246, 0.1));
        """)
        left_layout.addWidget(title_label)

        # 文本输入区域
        text_label = QLabel("输入文本:")
        text_label.setStyleSheet("margin-top: 5px;")  # 减小文本标签的上边距
        left_layout.addWidget(text_label)

        self.text_input = QTextEdit()
        self.text_input.setPlaceholderText("在此输入要转换的文本...")
        self.text_input.setStyleSheet("""
            QTextEdit {
                border: 2px solid #e2e8f0;
                border-radius: 16px;
                padding: 20px;
                background-color: #ffffff;
                font-size: 14px;
                color: #334155;
                selection-background-color: #3b82f6;
                selection-color: white;
                min-height: 160px;
                max-height: 280px;
                margin-top: 0px;
                margin-bottom: 5px;
            }
            QTextEdit:focus {
                border-color: #3b82f6;
                background-color: #f8fafc;
            }
            QTextEdit:hover {
                border-color: #94a3b8;
            }
        """)
        left_layout.addWidget(self.text_input)

        # 字数统计标签
        self.char_count_label = QLabel("字符数：0")
        self.char_count_label.setAlignment(Qt.AlignRight)
        self.char_count_label.setStyleSheet("""
            font-size: 13px;
            color: #64748b;
            margin: 5px 10px;
            padding: 8px 12px;
            background-color: rgba(248, 250, 252, 0.8);
            border-radius: 8px;
            min-height: 20px;
        """)
        left_layout.addWidget(self.char_count_label)

        # 语音选择区域
        voice_layout = QHBoxLayout()
        voice_label = QLabel("选择语音:")
        self.voice_combo = QComboBox()
        self.voice_combo.addItems(self.voice_mapping.keys())
        self.voice_combo.setMaxVisibleItems(10)  # 设置最大显示项数以适应更多语音选择
        
        # 添加性能提示标签
        self.voice_performance_tip = QLabel("推荐快速语音 | 中等速度 | 地区语音 | 方言语音")
        self.voice_performance_tip.setStyleSheet("""
            QLabel {
                font-size: 10px;
                color: #6c757d;
                padding: 2px 5px;
                background-color: #f8f9fa;
                border-radius: 3px;
                margin-top: 2px;
            }
        """)
        self.voice_performance_tip.setWordWrap(True)
        
        # 添加快速选择按钮
        self.quick_voice_btn = QPushButton("[快速] 快速语音")
        self.quick_voice_btn.setStyleSheet("""
            QPushButton {
                background-color: #28a745;
                color: white;
                border: none;
                border-radius: 4px;
                padding: 4px 8px;
                font-size: 11px;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #218838;
            }
        """)
        self.quick_voice_btn.clicked.connect(self.select_fastest_voice)
        self.quick_voice_btn.setFixedWidth(80)
        self.voice_combo.setStyleSheet("""
            QComboBox {
                border: 2px solid #e8e8e8;
                border-radius: 10px;
                padding: 10px 15px;
                background-color: #ffffff;
                font-size: 14px;
                color: #2c3e50;
                min-width: 280px;
            }
            QComboBox:hover {
                border-color: #3498db;
            }
            QComboBox::drop-down {
                border: none;
                width: 30px;
            }
            QComboBox::down-arrow {
                image: none;
                border-left: 6px solid transparent;
                border-right: 6px solid transparent;
                border-top: 6px solid #2c3e50;
                margin-right: 15px;
            }
            QComboBox QListView {
                border: 1px solid #e8e8e8;
                background-color: #ffffff;
                outline: 0px;
                padding: 5px;
            }
            QComboBox QListView::item {
                padding-top: 8px;
                padding-bottom: 8px;
                padding-left: 8px;
                min-height: 25px;
            }
            QComboBox QListView::item:hover {
                background-color: #f5f5f5;
            }
            QComboBox QListView::item:selected {
                background-color: #3498db;
                color: #ffffff;
            }
            QComboBox::drop-down:on {
                border: none;
            }
        """)
        self.voice_combo.view().window().setWindowFlags(Qt.Popup | Qt.FramelessWindowHint | Qt.NoDropShadowWindowHint)
        self.voice_combo.view().window().setAttribute(Qt.WA_TranslucentBackground)
        
        voice_layout.addWidget(voice_label)
        voice_layout.addWidget(self.voice_combo)
        voice_layout.addWidget(self.quick_voice_btn)
        voice_layout.addStretch()
        left_layout.addLayout(voice_layout)
        left_layout.addWidget(self.voice_performance_tip)

        # 语速控制
        speed_layout = QHBoxLayout()
        speed_label = QLabel("语速调节:")
        self.speed_slider = QSlider(Qt.Horizontal)
        self.speed_slider.setMinimum(50)
        self.speed_slider.setMaximum(200)
        self.speed_slider.setValue(100)
        self.speed_slider.setTickPosition(QSlider.TicksBelow)
        self.speed_slider.setTickInterval(25)

        self.speed_value_label = QLabel("1.0x")
        self.speed_value_label.setStyleSheet("min-width: 50px; margin-left: 10px;")
        self.speed_slider.valueChanged.connect(self.update_speed_label)

        speed_layout.addWidget(speed_label)
        speed_layout.addWidget(self.speed_slider)
        speed_layout.addWidget(self.speed_value_label)
        left_layout.addLayout(speed_layout)

        # 按钮区域 - 改为两行布局
        button_layout_container = QVBoxLayout()
        
        # 第一行：文件导入按钮
        file_button_layout = QHBoxLayout()
        
        # 单文件导入按钮
        self.import_file_button = QPushButton("📁 导入文件")
        self.import_file_button.clicked.connect(self.import_file)
        self.import_file_button.setStyleSheet("""
            background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                       stop:0 #8b5cf6, stop:1 #7c3aed);
            color: white;
            border: none;
            border-radius: 12px;
            padding: 14px 20px;
            font-size: 13px;
            font-weight: 600;
            min-width: 100px;
            margin: 6px;
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
        """)
        self.import_file_button.setProperty("class", "file-button")
        

        
        file_button_layout.addWidget(self.import_file_button)
        file_button_layout.addStretch()
        
        # 第二行：清空和转换按钮
        main_button_layout = QHBoxLayout()
        self.clear_button = QPushButton("清空文本")
        self.clear_button.clicked.connect(self.clear_text)
        self.clear_button.setStyleSheet("""
            background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                       stop:0 #64748b, stop:1 #475569);
            color: white;
            border: none;
            border-radius: 12px;
            padding: 14px 28px;
            font-size: 14px;
            font-weight: 600;
            min-width: 140px;
            margin: 8px;
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
        """)
        self.clear_button.setProperty("class", "secondary-button")

        self.convert_button = QPushButton("开始转换")
        self.convert_button.clicked.connect(self.start_conversion)
        self.convert_button.setStyleSheet("""
            background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                       stop:0 #10b981, stop:1 #059669);
            color: white;
            border: none;
            border-radius: 12px;
            padding: 14px 28px;
            font-size: 14px;
            font-weight: 600;
            min-width: 140px;
            margin: 8px;
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
        """)
        self.convert_button.setProperty("class", "primary-button")

        main_button_layout.addWidget(self.clear_button)
        main_button_layout.addWidget(self.convert_button)
        
        button_layout_container.addLayout(file_button_layout)
        button_layout_container.addLayout(main_button_layout)
        left_layout.addLayout(button_layout_container)

        # 进度条
        self.progress_bar = QProgressBar()
        self.progress_bar.setVisible(False)
        left_layout.addWidget(self.progress_bar)

        # 性能面板已移动到右侧，这里不再需要重复创建

        # 状态标签
        self.status_label = QLabel()
        self.status_label.setAlignment(Qt.AlignCenter)
        self.status_label.setStyleSheet("""
            font-size: 13px;
            margin: 10px 0;
            padding: 5px;
            border-radius: 5px;
        """)
        left_layout.addWidget(self.status_label)
        


        # 连接信号
        self.text_input.textChanged.connect(self.update_char_count)
        
        # 初始化字符数统计
        self.update_char_count()

        # 添加底部空间
        left_layout.addStretch()
        
        # 创建右侧性能监控面板
        self.create_performance_panel()
        
        # 将左右两个面板添加到主布局
        main_layout.addWidget(left_widget, 3)  # 左侧占比重为3
        main_layout.addWidget(self.right_panel, 2)  # 右侧占比重为2，给性能监控面板更多空间
        print(f"[调试] 主布局添加完成: 子控件数量={main_layout.count()}")

    def create_performance_panel(self):
        """创建右侧性能监控面板"""
        if HAS_PERFORMANCE_MONITOR:
            # 使用完整的性能监控组件
            self.right_panel = PerformanceMonitorWidget(self)
            print("[信息] 使用完整性能监控面板")
        else:
            # 使用简化的状态面板
            self.right_panel = self.create_simple_status_panel()
            print("[信息] 使用简化状态面板")
        
        # 默认显示面板
        self.right_panel.setVisible(True)
        print(f"[调试] 右侧面板创建完成: 可见={self.right_panel.isVisible()}")

    def create_simple_status_panel(self):
        """创建简化的状态面板"""
        from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel
        
        panel = QWidget()
        panel.setStyleSheet("""
            QWidget {
                background-color: #f8fafc;
                border-radius: 12px;
                margin: 5px;
            }
            QLabel {
                color: #1e293b;
                font-size: 12px;
                padding: 8px;
                margin: 2px;
                background-color: #ffffff;
                border-radius: 6px;
                border: 1px solid #e2e8f0;
            }
        """)
        
        layout = QVBoxLayout(panel)
        layout.setContentsMargins(15, 15, 15, 15)
        layout.setSpacing(10)
        
        # 标题
        title_label = QLabel("[状态] 转换状态")
        title_label.setStyleSheet("""
            font-size: 16px;
            font-weight: bold;
            color: #3b82f6;
            background-color: transparent;
            border: none;
            padding: 10px 0;
        """)
        layout.addWidget(title_label)
        
        # 状态标签
        self.simple_status_label = QLabel("等待开始转换...")
        layout.addWidget(self.simple_status_label)
        
        # 进度信息
        self.simple_progress_label = QLabel("进度: 0%")
        layout.addWidget(self.simple_progress_label)
        
        # 添加弹性空间
        layout.addStretch()
        
        # 添加简化的方法
        def update_processing_stats(stats):
            if hasattr(self, 'simple_status_label'):
                status_text = f"线程数: {stats.get('threads', 0)}\n"
                status_text += f"处理段数: {stats.get('completed', 0)}/{stats.get('total_segments', 0)}\n"
                status_text += f"处理时间: {stats.get('processing_time', 0):.0f}s"
                self.simple_status_label.setText(status_text)
        
        def add_performance_record(text_length, segments_count, total_time, speed_boost):
            if hasattr(self, 'simple_status_label'):
                self.simple_status_label.setText(f"[完成] 转换完成\n文本长度: {text_length}字\n用时: {total_time:.1f}秒")
        
        def cleanup():
            pass
            
        # 绑定方法
        panel.update_processing_stats = update_processing_stats
        panel.add_performance_record = add_performance_record
        panel.cleanup = cleanup
        
        return panel

    def on_performance_updated(self, data):
        """处理性能更新信号"""
        # 这里可以添加额外的处理逻辑
        pass
    
    def reset_performance_stats(self):
        """重置性能统计显示"""
        try:
            if hasattr(self, 'right_panel') and hasattr(self.right_panel, 'update_processing_stats'):
                # 重置所有统计数据为初始状态
                reset_stats = {
                    'threads': 0,
                    'total_segments': 0,
                    'active_tasks': 0,
                    'processing_time': 0.0,
                    'completed': 0,
                    'speed_ratio': 1.0,
                    'avg_segment_time': 0.0
                }
                self.right_panel.update_processing_stats(reset_stats)
                print("[调试] 性能统计已重置")
        except Exception as e:
            print(f"[错误] 重置性能统计失败: {e}")

    def update_processing_stats(self, threads=0, total_segments=0, active_tasks=0, 
                               processing_time=0.0, completed=0, speed_ratio=1.0, avg_segment_time=0.0):
        """更新处理统计信息到性能监控组件"""
        try:
            if hasattr(self, 'right_panel'):
                stats = {
                    'threads': threads,
                    'total_segments': total_segments,
                    'active_tasks': active_tasks,
                    'processing_time': processing_time,
                    'completed': completed,
                    'speed_ratio': speed_ratio,
                    'avg_segment_time': avg_segment_time
                }
                print(f"[调试] 更新性能统计: {stats}")
                
                # 检查right_panel是否有update_processing_stats方法
                if hasattr(self.right_panel, 'update_processing_stats'):
                    self.right_panel.update_processing_stats(stats)
                    print("[调试] 性能统计已发送到监控面板")
                else:
                    print(f"[警告] right_panel没有update_processing_stats方法，类型: {type(self.right_panel)}")
            else:
                print("[警告] 没有找到right_panel属性")
        except Exception as e:
            print(f"[错误] 更新性能统计失败: {e}")
            import traceback
            traceback.print_exc()


    

    

    def select_fastest_voice(self):
        """选择最快的语音选项"""
        # 找到第一个带[快速]标识的语音（最快速度）
        for voice_name in self.voice_mapping.keys():
            if "快速" in voice_name or "标准" in voice_name:
                # 设置为当前选择
                self.voice_combo.setCurrentText(voice_name)
                print(f"[信息] 已切换到快速语音: {voice_name}")
                break
    
    def add_performance_record(self, text_length, segments_count, total_time, speed_boost):
        """添加性能记录到历史"""
        try:
            from datetime import datetime
            
            # 创建记录
            record = {
                'timestamp': datetime.now(),
                'text_length': text_length,
                'segments_count': segments_count,
                'total_time': total_time,
                'speed_boost': speed_boost,
                'words_per_min': (text_length / total_time * 60) if total_time > 0 else 0
            }
            
            # 添加到历史记录
            self.performance_history.append(record)
            
            # 保持历史记录大小限制
            if len(self.performance_history) > self.max_history_size:
                self.performance_history.pop(0)
            
            # 更新历史显示
            self.update_performance_history_display()
            
        except Exception as e:
            print(f"添加性能记录时出错: {e}")
    
    def update_performance_history_display(self):
        """更新性能历史显示"""
        try:
            # 清空现有显示
            for i in reversed(range(self.history_layout.count())):
                child = self.history_layout.itemAt(i).widget()
                if child:
                    child.setParent(None)
            
            if not self.performance_history:
                # 没有记录时显示提示
                no_history_label = QLabel("暂无转换记录")
                no_history_label.setStyleSheet("""
                    color: #6c757d;
                    font-size: 11px;
                    padding: 5px;
                    text-align: center;
                """)
                no_history_label.setAlignment(Qt.AlignCenter)
                self.history_layout.addWidget(no_history_label)
            else:
                # 显示最近的记录（最新的在上面）
                for record in reversed(self.performance_history[-5:]):  # 只显示最近5条
                    time_str = record['timestamp'].strftime("%H:%M:%S")
                    
                    # 创建记录项
                    record_widget = QWidget()
                    record_widget.setStyleSheet("""
                        QWidget {
                            background-color: #ffffff;
                            border: 1px solid #e9ecef;
                            border-radius: 3px;
                            margin: 1px 0;
                        }
                    """)
                    
                    record_layout = QVBoxLayout(record_widget)
                    record_layout.setContentsMargins(6, 4, 6, 4)
                    record_layout.setSpacing(2)
                    
                    # 时间和加速倍数
                    header_label = QLabel(f"[时间] {time_str} | [倍速] {record['speed_boost']:.1f}x")
                    header_label.setStyleSheet("""
                        color: #495057;
                        font-size: 10px;
                        font-weight: bold;
                    """)
                    record_layout.addWidget(header_label)
                    
                    # 详细信息
                    details_label = QLabel(f"[文本] {record['text_length']}字 | [时间] {int(record['total_time'])}s | [段落] {record['segments_count']}段")
                    details_label.setStyleSheet("""
                        color: #6c757d;
                        font-size: 9px;
                    """)
                    record_layout.addWidget(details_label)
                    
                    self.history_layout.addWidget(record_widget)
                
                # 添加统计摘要
                if len(self.performance_history) >= 2:
                    avg_boost = sum(r['speed_boost'] for r in self.performance_history) / len(self.performance_history)
                    total_chars = sum(r['text_length'] for r in self.performance_history)
                    
                    summary_widget = QWidget()
                    summary_widget.setStyleSheet("""
                        QWidget {
                            background-color: #e7f3ff;
                            border: 1px solid #b3d9ff;
                            border-radius: 3px;
                            margin: 2px 0;
                        }
                    """)
                    
                    summary_layout = QVBoxLayout(summary_widget)
                    summary_layout.setContentsMargins(6, 4, 6, 4)
                    summary_layout.setSpacing(1)
                    
                    summary_label = QLabel("[统计] 统计摘要")
                    summary_label.setStyleSheet("""
                        color: #0066cc;
                        font-size: 10px;
                        font-weight: bold;
                    """)
                    summary_layout.addWidget(summary_label)
                    
                    stats_label = QLabel(f"平均加速: {avg_boost:.0f}x | 总计处理: {total_chars}字")
                    stats_label.setStyleSheet("""
                        color: #0066cc;
                        font-size: 9px;
                    """)
                    summary_layout.addWidget(stats_label)
                    
                    self.history_layout.addWidget(summary_widget)
            
            # 添加弹性空间
            self.history_layout.addStretch()
            
        except Exception as e:
            print(f"更新性能历史显示时出错: {e}")



    def update_speed_label(self):
        """更新语速标签"""
        speed = self.speed_slider.value() / 100
        self.speed_value_label.setText(f"{speed:.1f}x")

    def clear_text(self):
        """清空文本输入框"""
        self.text_input.clear()
        self.status_label.setText("")

    def import_file(self):
        """导入文件内容到文本框（增强版）"""
        try:
            file_path, _ = QFileDialog.getOpenFileName(
                self,
                "选择要导入的文件",
                "",
                "所有支持的文件 (*.txt *.docx *.pdf *.md *.rtf *.json *.csv *.xml *.html *.srt *.epub);;文本文件 (*.txt *.md);;Word文档 (*.docx);;PDF文件 (*.pdf);;RTF文件 (*.rtf);;JSON文件 (*.json);;CSV文件 (*.csv);;XML文件 (*.xml);;HTML文件 (*.html);;字幕文件 (*.srt);;电子书 (*.epub);;所有文件 (*.*)"
            )
            
            if not file_path:
                return
                
            # 显示加载状态
            self.status_label.setText("正在读取文件...")
            self.status_label.setStyleSheet("color: #2196F3;")
            
            # 根据文件扩展名选择读取方法
            file_ext = os.path.splitext(file_path)[1].lower()
            content = ""
            
            # 文本类文件
            if file_ext in ['.txt', '.md']:
                content = self.read_text_file(file_path)
            # Office文档
            elif file_ext == '.docx':
                content = self.read_docx_file(file_path)
            # PDF文档
            elif file_ext == '.pdf':
                content = self.read_pdf_file(file_path)
            # RTF文件
            elif file_ext == '.rtf':
                content = self.read_rtf_file(file_path)
            # JSON文件
            elif file_ext == '.json':
                content = self.read_json_file(file_path)
            # CSV文件
            elif file_ext == '.csv':
                content = self.read_csv_file(file_path)
            # XML文件
            elif file_ext == '.xml':
                content = self.read_xml_file(file_path)
            # HTML文件
            elif file_ext == '.html' or file_ext == '.htm':
                content = self.read_html_file(file_path)
            # 字幕文件
            elif file_ext == '.srt':
                content = self.read_srt_file(file_path)
            # 电子书
            elif file_ext == '.epub':
                content = self.read_epub_file(file_path)
            else:
                # 未知文件类型，尝试按文本文件读取
                content = self.read_text_file(file_path)
            
            if content:
                # 清空现有内容并插入新内容
                self.text_input.clear()
                self.text_input.setPlainText(content)
                
                # 显示成功信息和统计
                file_name = os.path.basename(file_path)
                char_count = len(content)
                word_count = len(content.split())
                line_count = content.count('\n') + 1
                
                # 估算语音时长（按中文每分钟350字计算）
                estimated_minutes = char_count / 350
                if estimated_minutes < 1:
                    time_str = f"{estimated_minutes * 60:.0f}秒"
                else:
                    time_str = f"{estimated_minutes:.1f}分钟"
                
                self.status_label.setText(
                    f"[成功] 成功导入: {file_name}\n"
                    f"[统计] 统计: {char_count:,}字符 | {word_count:,}词 | {line_count:,}行\n"
                    f"⏱️ 预计时长: {time_str}"
                )
                self.status_label.setStyleSheet("color: #4CAF50; line-height: 1.3;")
                
                # 自动滚动到顶部
                cursor = self.text_input.textCursor()
                cursor.movePosition(cursor.Start)
                self.text_input.setTextCursor(cursor)
                
            else:
                self.status_label.setText("❌ 文件内容为空或读取失败")
                self.status_label.setStyleSheet("color: #f44336;")
                
        except Exception as e:
            error_msg = f"导入文件失败: {str(e)}"
            self.status_label.setText(error_msg)
            self.status_label.setStyleSheet("color: #f44336;")
            print(f"文件导入错误: {e}")

    def read_text_file(self, file_path):
        """读取文本文件（自动检测编码）"""
        try:
            # 首先检测文件编码
            with open(file_path, 'rb') as f:
                raw_data = f.read()
                encoding_result = chardet.detect(raw_data)
                encoding = encoding_result['encoding']
                
            # 如果检测不到编码，尝试常见编码
            if not encoding:
                for enc in ['utf-8', 'gbk', 'gb2312', 'utf-16']:
                    try:
                        with open(file_path, 'r', encoding=enc) as f:
                            return f.read()
                    except UnicodeDecodeError:
                        continue
                        
            # 使用检测到的编码读取文件
            with open(file_path, 'r', encoding=encoding) as f:
                return f.read()
                
        except (IOError, OSError, PermissionError) as e:
            print(f"读取文本文件出错: {type(e).__name__}: {e}")
            return ""
        except UnicodeDecodeError as e:
            print(f"文本编码错误: {e}")
            # 最后尝试用UTF-8忽略错误读取
            try:
                with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                    return f.read()
            except (IOError, OSError):
                return ""

    def read_docx_file(self, file_path):
        """读取Word文档"""
        try:
            # 尝试导入python-docx
            try:
                from docx import Document
            except ImportError:
                # 如果没有安装python-docx，提示用户
                self.status_label.setText("❌ 需要安装python-docx库才能读取Word文档\n请运行: pip install python-docx")
                self.status_label.setStyleSheet("color: #f44336;")
                return ""
            
            doc = Document(file_path)
            content = []
            
            # 读取所有段落
            for paragraph in doc.paragraphs:
                text = paragraph.text.strip()
                if text:
                    content.append(text)
            
            return '\n\n'.join(content)
            
        except Exception as e:
            print(f"读取Word文档出错: {e}")
            return ""

    def read_pdf_file(self, file_path):
        """读取PDF文件"""
        try:
            # 尝试导入PyPDF2
            try:
                import PyPDF2
            except ImportError:
                # 如果没有安装PyPDF2，提示用户
                self.status_label.setText("❌ 需要安装PyPDF2库才能读取PDF文件\n请运行: pip install PyPDF2")
                self.status_label.setStyleSheet("color: #f44336;")
                return ""
            
            content = []
            
            with open(file_path, 'rb') as f:
                pdf_reader = PyPDF2.PdfReader(f)
                
                # 读取所有页面
                for page_num in range(len(pdf_reader.pages)):
                    page = pdf_reader.pages[page_num]
                    text = page.extract_text()
                    if text.strip():
                        content.append(text.strip())
            
            return '\n\n'.join(content)
            
        except Exception as e:
            print(f"读取PDF文件出错: {e}")
            return ""

    def read_rtf_file(self, file_path):
        """读取RTF文件"""
        try:
            # 尝试导入striprtf
            try:
                from striprtf.striprtf import rtf_to_text
            except ImportError:
                # 如果没有安装striprtf，提示用户
                self.status_label.setText("❌ 需要安装striprtf库才能读取RTF文件\n请运行: pip install striprtf")
                self.status_label.setStyleSheet("color: #f44336;")
                return ""
            
            with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                rtf_content = f.read()
                return rtf_to_text(rtf_content)
                
        except Exception as e:
            print(f"读取RTF文件出错: {e}")
            return ""

    def read_json_file(self, file_path):
        """读取JSON文件"""
        try:
            content = []
            with open(file_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
                
            # 递归提取JSON中的所有文本内容
            def extract_text(obj, path=""):
                if isinstance(obj, dict):
                    for key, value in obj.items():
                        extract_text(value, f"{path}.{key}" if path else key)
                elif isinstance(obj, list):
                    for i, item in enumerate(obj):
                        extract_text(item, f"{path}[{i}]" if path else f"[{i}]")
                elif isinstance(obj, str) and obj.strip():
                    # 只保留有意义的文本，跳过单个字符或纯数字
                    if len(obj.strip()) > 3 and not obj.isdigit():
                        content.append(obj.strip())
                        
            extract_text(data)
            return '\n\n'.join(content) if content else "JSON文件中未找到可用的文本内容"
            
        except json.JSONDecodeError as e:
            print(f"JSON解析错误: {e}")
            return ""
        except (IOError, OSError, PermissionError) as e:
            print(f"读取JSON文件出错: {type(e).__name__}: {e}")
            return ""
        except UnicodeDecodeError as e:
            print(f"JSON文件编码错误: {e}")
            return ""

    def read_csv_file(self, file_path):
        """读取CSV文件"""
        try:
            content = []
            
            # 尝试不同的编码
            for encoding in ['utf-8', 'gbk', 'gb2312']:
                try:
                    with open(file_path, 'r', encoding=encoding, newline='') as f:
                        reader = csv.reader(f)
                        rows = list(reader)
                        break
                except UnicodeDecodeError:
                    continue
            else:
                # 如果所有编码都失败，使用错误忽略模式
                with open(file_path, 'r', encoding='utf-8', errors='ignore', newline='') as f:
                    reader = csv.reader(f)
                    rows = list(reader)
            
            if not rows:
                return "CSV文件为空"
                
            # 将CSV内容转换为易读的文本格式
            for i, row in enumerate(rows):
                if i == 0:
                    # 第一行作为标题
                    content.append("标题：" + " | ".join(row))
                    content.append("-" * 50)
                else:
                    # 数据行
                    non_empty_cells = [cell.strip() for cell in row if cell.strip()]
                    if non_empty_cells:
                        content.append(f"第{i}行：" + " | ".join(non_empty_cells))
            
            return '\n'.join(content)
            
        except Exception as e:
            print(f"读取CSV文件出错: {e}")
            return ""

    def read_xml_file(self, file_path):
        """读取XML文件"""
        try:
            tree = ET.parse(file_path)
            root = tree.getroot()
            
            content = []
            
            def extract_text_from_element(element, path=""):
                # 添加元素名称作为标题
                if element.tag and not element.tag.startswith('{'):
                    current_path = f"{path}.{element.tag}" if path else element.tag
                    
                    # 如果元素有文本内容
                    if element.text and element.text.strip():
                        text = element.text.strip()
                        if len(text) > 3:  # 只保留有意义的文本
                            content.append(f"[{current_path}] {text}")
                    
                    # 处理属性
                    if element.attrib:
                        for attr, value in element.attrib.items():
                            if value and len(str(value).strip()) > 3:
                                content.append(f"[{current_path}@{attr}] {value}")
                    
                    # 递归处理子元素
                    for child in element:
                        extract_text_from_element(child, current_path)
                        
            extract_text_from_element(root)
            
            return '\n'.join(content) if content else "XML文件中未找到可用的文本内容"
            
        except ET.ParseError as e:
            print(f"XML解析错误: {e}")
            return ""
        except (IOError, OSError, PermissionError) as e:
            print(f"读取XML文件出错: {type(e).__name__}: {e}")
            return ""

    def read_html_file(self, file_path):
        """读取HTML文件"""
        try:
            # 尝试导入BeautifulSoup
            try:
                from bs4 import BeautifulSoup
            except ImportError:
                # 如果没有安装BeautifulSoup，使用简单的文本提取
                return self._read_html_simple(file_path)
            
            with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                html_content = f.read()
            
            soup = BeautifulSoup(html_content, 'html.parser')
            
            # 移除脚本和样式标签
            for script in soup(["script", "style"]):
                script.decompose()
            
            # 提取文本内容
            content = []
            
            # 标题
            title = soup.find('title')
            if title and title.get_text().strip():
                content.append(f"标题：{title.get_text().strip()}")
                content.append("")
            
            # 主要内容标签
            for tag in ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']:
                headers = soup.find_all(tag)
                for header in headers:
                    text = header.get_text().strip()
                    if text and len(text) > 2:
                        content.append(f"【{tag.upper()}】{text}")
            
            # 段落内容
            paragraphs = soup.find_all(['p', 'div', 'article', 'section'])
            for p in paragraphs:
                text = p.get_text().strip()
                if text and len(text) > 10:  # 只保留较长的段落
                    content.append(text)
            
            return '\n\n'.join(content) if content else "HTML文件中未找到可用的文本内容"
            
        except Exception as e:
            print(f"读取HTML文件出错: {e}")
            return self._read_html_simple(file_path)

    def _read_html_simple(self, file_path):
        """简单的HTML文本提取（不依赖BeautifulSoup）"""
        try:
            import re
            
            with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                html_content = f.read()
            
            # 移除脚本和样式
            html_content = re.sub(r'<script[^>]*>.*?</script>', '', html_content, flags=re.DOTALL | re.IGNORECASE)
            html_content = re.sub(r'<style[^>]*>.*?</style>', '', html_content, flags=re.DOTALL | re.IGNORECASE)
            
            # 移除HTML标签
            html_content = re.sub(r'<[^>]+>', ' ', html_content)
            
            # 清理空白字符
            html_content = re.sub(r'\s+', ' ', html_content)
            
            return html_content.strip()
            
        except Exception as e:
            print(f"简单HTML读取出错: {e}")
            return ""

    def read_srt_file(self, file_path):
        """读取SRT字幕文件"""
        try:
            content = []
            
            with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                lines = f.readlines()
            
            current_subtitle = {}
            subtitle_text = []
            
            for line in lines:
                line = line.strip()
                
                if not line:
                    # 空行表示一个字幕块结束
                    if subtitle_text:
                        content.extend(subtitle_text)
                        subtitle_text = []
                    current_subtitle = {}
                elif line.isdigit():
                    # 字幕序号
                    current_subtitle['index'] = line
                elif '-->' in line:
                    # 时间轴行，跳过
                    continue
                else:
                    # 字幕文本
                    subtitle_text.append(line)
            
            # 处理最后一个字幕块
            if subtitle_text:
                content.extend(subtitle_text)
            
            return '\n'.join(content) if content else "字幕文件中未找到文本内容"
            
        except Exception as e:
            print(f"读取SRT文件出错: {e}")
            return ""

    def read_epub_file(self, file_path):
        """读取EPUB电子书文件"""
        try:
            # 尝试导入ebooklib
            try:
                import ebooklib
                from ebooklib import epub
            except ImportError:
                self.status_label.setText("❌ 需要安装ebooklib库才能读取EPUB文件\n请运行: pip install ebooklib")
                self.status_label.setStyleSheet("color: #f44336;")
                return ""
            
            book = epub.read_epub(file_path)
            content = []
            
            # 获取书籍信息
            title = book.get_metadata('DC', 'title')
            if title:
                content.append(f"书名：{title[0][0]}")
            
            creator = book.get_metadata('DC', 'creator')
            if creator:
                content.append(f"作者：{creator[0][0]}")
            
            content.append("-" * 50)
            
            # 提取章节内容
            for item in book.get_items():
                if item.get_type() == ebooklib.ITEM_DOCUMENT:
                    # 使用BeautifulSoup解析HTML内容
                    try:
                        from bs4 import BeautifulSoup
                        soup = BeautifulSoup(item.get_content(), 'html.parser')
                        
                        # 移除脚本和样式
                        for script in soup(["script", "style"]):
                            script.decompose()
                        
                        text = soup.get_text()
                        # 清理多余的空白字符
                        text = '\n'.join(line.strip() for line in text.splitlines() if line.strip())
                        
                        if text and len(text) > 100:  # 只保留较长的章节
                            content.append(text)
                            content.append("")  # 章节间空行
                            
                    except ImportError:
                        # 如果没有BeautifulSoup，使用简单的文本提取
                        import re
                        text = item.get_content().decode('utf-8', errors='ignore')
                        text = re.sub(r'<[^>]+>', ' ', text)
                        text = re.sub(r'\s+', ' ', text)
                        if text and len(text) > 100:
                            content.append(text.strip())
                            content.append("")
            
            return '\n\n'.join(content) if content else "EPUB文件中未找到可用的文本内容"
            
        except Exception as e:
            print(f"读取EPUB文件出错: {e}")
            return ""

    def update_char_count(self):
        """更新字符数统计"""
        try:
            text = self.text_input.toPlainText()
            char_count = len(text)
            
            # 更新显示
            base_style = """
                font-size: 13px;
                margin: 5px 10px;
                padding: 8px 12px;
                background-color: rgba(248, 250, 252, 0.8);
                border-radius: 8px;
                min-height: 20px;
            """
            
            if char_count == 0:
                self.char_count_label.setText("字符数：0")
                self.char_count_label.setStyleSheet(base_style + """
                    color: #64748b;
                """)
            elif char_count > 1000:
                # 显示分段信息，使用与转换逻辑完全一致的分段算法
                try:
                    segments = len(self.split_text_for_display(text))
                    self.char_count_label.setText(f"字符数：{char_count:,}\n（预计分为 {segments} 段）")
                except Exception:
                    # 如果分段计算失败，只显示字符数
                    self.char_count_label.setText(f"字符数：{char_count:,}")
                
                self.char_count_label.setStyleSheet(base_style + """
                    color: #f59e0b;
                    background-color: rgba(253, 230, 138, 0.3);
                    line-height: 1.3;
                """)
            else:
                self.char_count_label.setText(f"字符数：{char_count:,}")
                self.char_count_label.setStyleSheet(base_style + """
                    color: #059669;
                    background-color: rgba(167, 243, 208, 0.3);
                """)
        except Exception as e:
            # 如果字符数统计失败，显示安全的默认值
            print(f"字符数统计出错: {e}")
            try:
                self.char_count_label.setText("字符数：计算中...")
                self.char_count_label.setStyleSheet("""
                    font-size: 13px;
                    color: #64748b;
                    margin: 5px 10px;
                    padding: 8px 12px;
                    background-color: rgba(248, 250, 252, 0.8);
                    border-radius: 8px;
                    min-height: 20px;
                """)
            except:
                pass

    def start_conversion(self):
        """开始转换"""
        try:
            text = self.text_input.toPlainText().strip()
            if not text:
                self.status_label.setText("请输入要转换的文本")
                self.status_label.setStyleSheet("color: #f44336;")
                return
        except Exception as e:
            print(f"获取文本时出错: {e}")
            self.status_label.setText("获取文本内容时出错，请重试")
            self.status_label.setStyleSheet("color: #f44336;")
            return

        # 选择保存位置
        try:
            output_file, _ = QFileDialog.getSaveFileName(
                self,
                "选择保存位置",
                os.path.join(os.getcwd(), "output.mp3"),
                "音频文件 (*.mp3)"
            )

            if not output_file:
                return
        except Exception as e:
            print(f"文件对话框出错: {e}")
            self.status_label.setText("文件对话框出错，请重试")
            self.status_label.setStyleSheet("color: #f44336;")
            return

        # 创建保存目录（如果需要）
        output_dir = os.path.dirname(output_file)
        if output_dir:  # 只有非空路径才创建目录
            os.makedirs(output_dir, exist_ok=True)

        # 获取选择的语音和语速
        voice = self.voice_mapping[self.voice_combo.currentText()]
        speed = self.speed_slider.value() / 100

        # 显示进度条
        self.progress_bar.setVisible(True)
        self.progress_bar.setValue(0)
        self.status_label.setText("正在转换...")
        self.status_label.setStyleSheet("color: #2196F3;")

        # 禁用按钮
        self.convert_button.setEnabled(False)
        
        # 初始化性能统计
        self.conversion_start_time = time.time()
        
        # 使用与转换逻辑完全一致的分段策略计算总段数
        self.total_segments = len(self.split_text_for_display(text))
        
        # 重置并更新统计信息
        self.reset_performance_stats()
        self.update_perf_stats()
        
        # 启动性能统计定时器
        self.perf_timer = QTimer()
        self.perf_timer.timeout.connect(self.update_perf_stats)
        self.perf_timer.start(1000)  # 每1000ms更新一次，与频率限制保持一致

        # 创建并启动转换线程
        self.worker = ConversionWorker(text, output_file, voice, speed)
        self.worker.progress.connect(self.update_progress)
        self.worker.finished.connect(self.conversion_finished)
        self.worker.start()

    def update_progress(self, value):
        """更新进度条"""
        self.progress_bar.setValue(value)
        # 同时更新简化面板的进度显示
        if hasattr(self, 'simple_progress_label'):
            self.simple_progress_label.setText(f"进度: {value}%")

    def conversion_finished(self, success, message):
        """转换完成的处理"""
        self.convert_button.setEnabled(True)
        
        # 停止性能统计定时器
        if hasattr(self, 'perf_timer'):
            self.perf_timer.stop()
        
        # 最后一次更新性能统计
        self.update_perf_stats(final=True)
        
        # 添加性能记录到历史
        if success and hasattr(self, 'conversion_start_time') and hasattr(self, 'worker'):
            try:
                total_time = time.time() - self.conversion_start_time
                text_length = len(self.worker.text)
                segments_count = self.worker.actual_segments_count
                
                # 计算实际加速倍数
                if hasattr(self.worker, 'thread_pool'):
                    max_workers = self.worker.thread_pool.max_workers
                    theoretical_speedup = min(max_workers, segments_count)
                    # 实际加速倍数会考虑网络延迟等因素，通常比理论值低一些
                    actual_speedup = theoretical_speedup * 0.7  # 经验系数
                else:
                    actual_speedup = 1.0
                
                # 添加到性能历史
                # 添加性能记录到新的监控组件
                if hasattr(self, 'right_panel'):
                    self.right_panel.add_performance_record(text_length, segments_count, total_time, actual_speedup)
                
            except Exception as e:
                print(f"添加性能记录时出错: {e}")

        if success:
            self.status_label.setText(message)
            self.status_label.setStyleSheet("color: #4CAF50;")
            # 跨平台打开输出目录
            self.open_output_directory()
        else:
            self.status_label.setText(message)
            self.status_label.setStyleSheet("color: #f44336;")

        # 使用QTimer延迟隐藏进度条，但保持性能面板可见
        QTimer.singleShot(3000, lambda: self.progress_bar.setVisible(False))

    def open_output_directory(self):
        """跨平台打开输出目录"""
        try:
            import platform
            output_dir = os.path.dirname(self.worker.output_file)
            
            system = platform.system()
            if system == "Windows":
                os.startfile(output_dir)
            elif system == "Darwin":  # macOS
                os.system(f'open "{output_dir}"')
            elif system == "Linux":
                os.system(f'xdg-open "{output_dir}"')
        except Exception as e:
            print(f"无法打开目录: {e}")

    def get_smart_segment_params(self, text_length):
        """根据文本长度和CPU核心数智能选择分段参数"""
        # 基础分段策略：根据推荐线程数调整
        base_segment_size = max(300, 1200 // self.recommended_threads)  # 基础分段大小
        
        if text_length < 1000:
            # 短文本：使用较大分段，减少并行开销
            max_length = min(1000, text_length)
            min_length = max(200, max_length // 2)
        elif text_length < 5000:
            # 中等文本：根据线程数适度分段
            max_length = max(base_segment_size, 600)
            min_length = max(150, max_length // 3)
        else:
            # 长文本：积极分段以充分利用多线程
            # 线程数越多，分段越小，但不低于最小阈值
            max_length = max(400, base_segment_size)
            min_length = max(100, max_length // 4)
        
        print(f"[策略] 智能分段策略: 文本长度={text_length}, 推荐线程={self.recommended_threads}, 分段大小={max_length}")
        return max_length, min_length

    def split_text_for_display(self, text, max_length=None, min_length=None):
        """分割文本用于显示段落数量（使用统一的TextSegmenter）"""
        try:
            # 使用与ConversionWorker相同的分段策略
            text_length = len(text)
            if text_length < 500:
                max_length, min_length = 1000, 500
            elif text_length < 3000:
                max_length, min_length = 800, 200
            else:
                max_length, min_length = 600, 150
            
            # 使用统一的TextSegmenter
            segmenter = TextSegmenter(text_length=text_length)
            return segmenter.split_text(text, max_length, min_length)
        except Exception as e:
            print(f"分段计算出错: {e}")
            # 使用简单的分割方法作为后备
            fallback_length = max_length if max_length else 800
            return [text[i:i+fallback_length] for i in range(0, len(text), fallback_length)]
    


    def update_perf_stats(self, final=False):
        """更新性能统计信息 - 优化版本（减少开销，增加缓存）"""
        try:
            # 限制更新频率，避免过于频繁的UI更新
            current_time = time.time()
            if not final and hasattr(self, '_last_perf_update'):
                if current_time - self._last_perf_update < 1.5:  # 调整到1.5秒
                    return
            self._last_perf_update = current_time
            
            # 计算处理时间
            elapsed_time = 0.0
            if hasattr(self, 'conversion_start_time'):
                elapsed_time = current_time - self.conversion_start_time
            
            # 缓存线程池状态（避免重复调用）
            if not hasattr(self, '_perf_cache'):
                self._perf_cache = {}
            
            cache = self._perf_cache
            max_workers = cache.get('max_workers', 0)
            total_segments = getattr(self, 'total_segments', 0)
            
            # 只在必要时更新活跃任务和完成任务数（这些调用可能有开销）
            active_tasks = 0
            completed_tasks = 0
            
            if hasattr(self, 'worker') and hasattr(self.worker, 'thread_pool'):
                thread_pool = self.worker.thread_pool
                
                # 缓存不变的值
                if 'max_workers' not in cache and hasattr(thread_pool, 'current_workers'):
                    max_workers = thread_pool.current_workers
                    cache['max_workers'] = max_workers
                
                # 只在最终更新或每3次更新时查询动态状态
                if final or not hasattr(self, '_perf_update_counter'):
                    self._perf_update_counter = 0
                
                self._perf_update_counter += 1
                
                if final or self._perf_update_counter % 3 == 0:
                    if hasattr(thread_pool, 'get_active_tasks'):
                        active_tasks = thread_pool.get_active_tasks()
                    if hasattr(thread_pool, 'completed_tasks'):
                        completed_tasks = thread_pool.completed_tasks
                else:
                    # 使用缓存值
                    active_tasks = cache.get('active_tasks', 0)
                    completed_tasks = cache.get('completed_tasks', 0)
                
                # 更新缓存
                cache['active_tasks'] = active_tasks
                cache['completed_tasks'] = completed_tasks
                
                # 计算加速倍数（理论值）
                theoretical_speedup = min(max_workers, total_segments) if total_segments > 0 else 1.0
            else:
                theoretical_speedup = 1.0
            
            # 计算平均段处理时间
            avg_segment_time = elapsed_time / max(1, total_segments) if total_segments > 0 else 0
            
            # 更新性能监控组件
            self.update_processing_stats(
                threads=max_workers,
                total_segments=total_segments,
                active_tasks=active_tasks,
                processing_time=elapsed_time,
                completed=completed_tasks,
                speed_ratio=theoretical_speedup,
                avg_segment_time=avg_segment_time
            )
                
        except (AttributeError, TypeError, ValueError) as e:
            # 静默处理常见错误
            if final:
                print(f"[调试] 性能统计更新失败: {e}")
        except Exception as e:
            # 记录未预期的错误
            print(f"[警告] 性能统计发生未预期的错误: {e}")





def main():
    app = QApplication(sys.argv)

    # 设置应用程序图标
    try:
        app.setWindowIcon(QIcon('icon.ico'))
    except:
        pass

    # 设置全局字体
    font = QFont("Microsoft YaHei UI", 9)
    app.setFont(font)

    window = TextToSpeechApp()
    window.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
